{
  "exportFormatVersion": 2,
  "exportTime": "2026-10-08 00:00:00",
  "containerVersion": {
    "path": "accounts/0000000000/containers/00000000/versions/0",
    "accountId": "0000000000",
    "containerId": "00000000",
    "containerVersionId": "0",
    "name": "TuriTop - custom thank-you page",
    "description": "GTM container for TuriTop purchases on a CUSTOM thank-you page (Custom Success URL): fires GA4 'purchase' and the Google Ads conversion on the page view, with the values of the URL, once per browser and destination while localStorage is available (if it is blocked, a reload can send the purchase again). Install it on the merchant's website, then edit only the three Constant variables (GA4 Measurement ID, Google Ads Conversion ID and Conversion Label).",
    "container": {
      "path": "accounts/0000000000/containers/00000000",
      "accountId": "0000000000",
      "containerId": "00000000",
      "name": "TuriTop Booking Widget",
      "publicId": "GTM-XXXXXXX",
      "usageContext": [
        "WEB"
      ]
    },
    "builtInVariable": [
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "type": "EVENT",
        "name": "Event"
      }
    ],
    "tag": [
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "tagId": "101",
        "name": "TuriTop Custom - GA4 - Purchase",
        "type": "gaawe",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "eventName",
            "value": "purchase"
          },
          {
            "type": "TEMPLATE",
            "key": "measurementIdOverride",
            "value": "{{Const - GA4 Measurement ID}}"
          },
          {
            "type": "LIST",
            "key": "eventParameters",
            "list": [
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "transaction_id"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - JS - URL transaction_id}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "value"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - JS - URL total}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "currency"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - URL - currency}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "item_id"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - URL - product_short_id}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "item_name"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - URL - product_name}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "company_short_id"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - URL - csid}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "site_url"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - JS - URL site_url}}"
                  }
                ]
              },
              {
                "type": "MAP",
                "map": [
                  {
                    "type": "TEMPLATE",
                    "key": "name",
                    "value": "payment_method"
                  },
                  {
                    "type": "TEMPLATE",
                    "key": "value",
                    "value": "{{TuriTop Custom - JS - URL payment_method}}"
                  }
                ]
              }
            ]
          }
        ],
        "firingTriggerId": [
          "11"
        ],
        "blockingTriggerId": [
          "12"
        ],
        "tagFiringOption": "ONCE_PER_EVENT",
        "consentSettings": {
          "consentStatus": "NEEDED",
          "consentType": {
            "type": "LIST",
            "list": [
              {
                "type": "TEMPLATE",
                "value": "analytics_storage"
              }
            ]
          }
        },
        "teardownTag": [
          {
            "tagName": "TuriTop Custom - Mark GA4 purchase as sent",
            "stopTeardownOnFailure": true
          }
        ],
        "notes": "Destination GA4 property is set via the Constant variable 'Const - GA4 Measurement ID'. Edit that variable, not this tag. Fires on the custom thank-you page (page view with the purchase in the URL), once per browser while localStorage is available (if it is blocked, a reload can send the purchase again). Needs analytics_storage consent."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "tagId": "102",
        "name": "TuriTop Custom - Google Ads - Conversion (Purchase)",
        "type": "awct",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "conversionId",
            "value": "{{Const - Google Ads Conversion ID}}"
          },
          {
            "type": "TEMPLATE",
            "key": "conversionLabel",
            "value": "{{Const - Google Ads Conversion Label}}"
          },
          {
            "type": "TEMPLATE",
            "key": "orderId",
            "value": "{{TuriTop Custom - JS - URL transaction_id}}"
          },
          {
            "type": "TEMPLATE",
            "key": "conversionValue",
            "value": "{{TuriTop Custom - JS - URL total}}"
          },
          {
            "type": "TEMPLATE",
            "key": "currencyCode",
            "value": "{{TuriTop Custom - URL - currency}}"
          }
        ],
        "firingTriggerId": [
          "11"
        ],
        "blockingTriggerId": [
          "13"
        ],
        "tagFiringOption": "ONCE_PER_EVENT",
        "consentSettings": {
          "consentStatus": "NEEDED",
          "consentType": {
            "type": "LIST",
            "list": [
              {
                "type": "TEMPLATE",
                "value": "ad_storage"
              }
            ]
          }
        },
        "teardownTag": [
          {
            "tagName": "TuriTop Custom - Mark Google Ads purchase as sent",
            "stopTeardownOnFailure": true
          }
        ],
        "notes": "Set 'Const - Google Ads Conversion ID' (numeric AW id) and 'Const - Google Ads Conversion Label'. orderId = transaction_id enables Google-side dedupe. Fires on the custom thank-you page, once per browser while localStorage is available (if it is blocked, a reload can send the purchase again). Needs ad_storage consent."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "tagId": "103",
        "name": "TuriTop Custom - Mark GA4 purchase as sent",
        "type": "html",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "html",
            "value": "<script>\n  // Marks the purchase of the custom thank-you page as sent to GA4, so a reload of\n  // the same page does not send it to GA4 again (read by 'TuriTop Custom - JS - GA4 purchase already sent').\n  (function () {\n    try {\n      var id = {{TuriTop Custom - JS - URL transaction_id}};\n      if (id) { window.localStorage.setItem('tt_purchase_ga4_' + id, '1'); }\n    } catch (e) {}\n  })();\n</script>"
          },
          {
            "type": "BOOLEAN",
            "key": "supportDocumentWrite",
            "value": "false"
          }
        ],
        "tagFiringOption": "ONCE_PER_EVENT",
        "notes": "Cleanup tag of 'TuriTop Custom - GA4 - Purchase': it has no trigger of its own and runs only after that tag fires, so a purchase blocked by consent is not marked. Writes localStorage key tt_purchase_ga4_{code} when the URL has a purchase code. One marker per destination, so consent granted for one destination does not block the other. Do not delete it: without it a reload sends the purchase to GA4 again."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "tagId": "104",
        "name": "TuriTop Custom - Mark Google Ads purchase as sent",
        "type": "html",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "html",
            "value": "<script>\n  // Marks the purchase of the custom thank-you page as sent to Google Ads, so a reload of\n  // the same page does not send it to Google Ads again (read by 'TuriTop Custom - JS - Ads purchase already sent').\n  (function () {\n    try {\n      var id = {{TuriTop Custom - JS - URL transaction_id}};\n      if (id) { window.localStorage.setItem('tt_purchase_ads_' + id, '1'); }\n    } catch (e) {}\n  })();\n</script>"
          },
          {
            "type": "BOOLEAN",
            "key": "supportDocumentWrite",
            "value": "false"
          }
        ],
        "tagFiringOption": "ONCE_PER_EVENT",
        "notes": "Cleanup tag of 'TuriTop Custom - Google Ads - Conversion (Purchase)': it has no trigger of its own and runs only after that tag fires, so a purchase blocked by consent is not marked. Writes localStorage key tt_purchase_ads_{code} when the URL has a purchase code. One marker per destination, so consent granted for one destination does not block the other. Do not delete it: without it a reload sends the purchase to Google Ads again."
      }
    ],
    "trigger": [
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "triggerId": "11",
        "name": "TuriTop Custom - Page View - Custom thank-you page",
        "type": "PAGEVIEW",
        "filter": [
          {
            "type": "EQUALS",
            "parameter": [
              {
                "type": "TEMPLATE",
                "key": "arg0",
                "value": "{{TuriTop Custom - JS - URL transaction_id}}"
              },
              {
                "type": "TEMPLATE",
                "key": "arg1",
                "value": "undefined"
              },
              {
                "type": "BOOLEAN",
                "key": "negate",
                "value": "true"
              }
            ]
          },
          {
            "type": "EQUALS",
            "parameter": [
              {
                "type": "TEMPLATE",
                "key": "arg0",
                "value": "{{TuriTop Custom - URL - payment_link}}"
              },
              {
                "type": "TEMPLATE",
                "key": "arg1",
                "value": "1"
              },
              {
                "type": "BOOLEAN",
                "key": "negate",
                "value": "true"
              }
            ]
          }
        ],
        "notes": "Custom thank-you page (Custom Success URL). Fires when the URL carries booking_id, booking_id[], shopping_cart_id or multiclient_hash and payment_link is not 1 (payment links are not purchases). Reload duplicates are blocked per tag by the exceptions 'TuriTop Custom - Block - GA4 purchase already sent' and 'TuriTop Custom - Block - Ads purchase already sent'."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "triggerId": "12",
        "name": "TuriTop Custom - Block - GA4 purchase already sent",
        "type": "PAGEVIEW",
        "filter": [
          {
            "type": "EQUALS",
            "parameter": [
              {
                "type": "TEMPLATE",
                "key": "arg0",
                "value": "{{TuriTop Custom - JS - GA4 purchase already sent}}"
              },
              {
                "type": "TEMPLATE",
                "key": "arg1",
                "value": "true"
              }
            ]
          }
        ],
        "notes": "Exception (blocking trigger) of 'TuriTop Custom - GA4 - Purchase': blocks it on the custom thank-you page when this browser already sent the purchase to that destination."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "triggerId": "13",
        "name": "TuriTop Custom - Block - Ads purchase already sent",
        "type": "PAGEVIEW",
        "filter": [
          {
            "type": "EQUALS",
            "parameter": [
              {
                "type": "TEMPLATE",
                "key": "arg0",
                "value": "{{TuriTop Custom - JS - Ads purchase already sent}}"
              },
              {
                "type": "TEMPLATE",
                "key": "arg1",
                "value": "true"
              }
            ]
          }
        ],
        "notes": "Exception (blocking trigger) of 'TuriTop Custom - Google Ads - Conversion (Purchase)': blocks it on the custom thank-you page when this browser already sent the purchase to that destination."
      }
    ],
    "variable": [
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "12",
        "name": "TuriTop Custom - JS - decode tt_attr (Custom Success URL)",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // Decodes tt_attr, the attribution that TuriTop appends to the Custom Success URL\n  // (Booking_lib::urlGetParams): base64url without padding of a JSON object with\n  // gclid/gbraid/wbraid/gad_source/utm_*, payment_method,\n  // site_url and, on resold bookings, reseller_csid / reseller_name.\n  // The bundled GA4 / Google Ads tags read only payment_method and site_url from it;\n  // gclid/gbraid/wbraid/gad_source/utm_* are exposed here for your own tags.\n  // Returns that object, or undefined when tt_attr is absent (long URLs can drop it:\n  // discard level 2, after product_description) or cannot be decoded. Never throws.\n  try {\n    var v = ({{TuriTop Custom - JS - URL params}})['tt_attr'];\n    if (!v || !v[0]) { return undefined; }\n    var s = v[0].replace(/ /g, '+').replace(/-/g, '+').replace(/_/g, '/');\n    while (s.length % 4) { s += '='; }\n    var o = JSON.parse(atob(s));\n    return Object.prototype.toString.call(o) === '[object Object]' ? o : undefined;\n  } catch (e) { return undefined; }\n}"
          }
        ],
        "notes": "Use ONLY on the Custom Success URL page. The bundled GA4 tag sends only payment_method and site_url from tt_attr and the Google Ads tag sends nothing from it; gclid/gbraid/wbraid/gad_source/utm_* are exposed for your own tags. On the postMessage fallback the attribution arrives as a dataLayer object instead (DLV - attribution)."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "13",
        "name": "Const - GA4 Measurement ID",
        "type": "c",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "value",
            "value": "G-XXXXXXXXXX"
          }
        ],
        "notes": "EDIT ME: your GA4 Measurement ID."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "14",
        "name": "Const - Google Ads Conversion ID",
        "type": "c",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "value",
            "value": "AW-XXXXXXXXXX"
          }
        ],
        "notes": "EDIT ME: your Google Ads conversion ID (the numeric AW id)."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "15",
        "name": "Const - Google Ads Conversion Label",
        "type": "c",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "value",
            "value": "XXXXXXXXXXXXXXXXXX"
          }
        ],
        "notes": "EDIT ME: your Google Ads conversion label."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "16",
        "name": "TuriTop Custom - JS - URL params",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // Query string of the page as { key: [values] }, URL-decoded. Keys keep their\n  // '[]' suffix (booking_id[], total[]), so array params from shopping carts and\n  // multiclient purchases are kept in order. Used only by the URL variables below.\n  var out = {};\n  var q = (document.location.search || '').replace(/^\\?/, '');\n  if (!q) { return out; }\n  var parts = q.split('&');\n  for (var i = 0; i < parts.length; i++) {\n    if (!parts[i]) { continue; }\n    var eq = parts[i].indexOf('=');\n    var k = eq < 0 ? parts[i] : parts[i].substring(0, eq);\n    var v = eq < 0 ? '' : parts[i].substring(eq + 1);\n    try {\n      k = decodeURIComponent(k.replace(/\\+/g, ' '));\n      v = decodeURIComponent(v.replace(/\\+/g, ' '));\n    } catch (e) { continue; }\n    if (!Object.prototype.hasOwnProperty.call(out, k)) { out[k] = []; }\n    out[k].push(v);\n  }\n  return out;\n}"
          }
        ],
        "notes": "Custom thank-you page. Internal helper of the JS - URL variables."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "17",
        "name": "TuriTop Custom - JS - URL transaction_id",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // Purchase code on the custom thank-you page: shopping cart > multiclient >\n  // booking (booking_id, else the first booking_id[]). undefined when the URL\n  // carries none of them, so the page is not a TuriTop thank-you page.\n  var p = {{TuriTop Custom - JS - URL params}};\n  var keys = ['shopping_cart_id', 'multiclient_hash', 'booking_id', 'booking_id[]'];\n  for (var i = 0; i < keys.length; i++) {\n    var v = p[keys[i]];\n    if (v && v.length && v[0]) { return v[0]; }\n  }\n  return undefined;\n}"
          }
        ],
        "notes": "Custom thank-you page. = transaction_id (dedupe key): shopping_cart_id, else multiclient_hash, else booking_id."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "18",
        "name": "TuriTop Custom - JS - URL total",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // Purchase value: the sum of total[] if the URL carries it (accepted for\n  // compatibility; TuriTop sends a single total, also for shopping carts), else total.\n  // undefined when there is no numeric amount in the URL.\n  var p = {{TuriTop Custom - JS - URL params}};\n  var list = (p['total[]'] && p['total[]'].length) ? p['total[]'] : (p['total'] || []);\n  var sum = 0;\n  var found = false;\n  for (var i = 0; i < list.length; i++) {\n    var n = parseFloat(list[i]);\n    if (!isNaN(n)) { sum += n; found = true; }\n  }\n  return found ? Math.round(sum * 100) / 100 : undefined;\n}"
          }
        ],
        "notes": "Custom thank-you page. = value."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "19",
        "name": "TuriTop Custom - JS - URL payment_method",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // payment_method packed in tt_attr. undefined when tt_attr is absent or invalid.\n  var a = {{TuriTop Custom - JS - decode tt_attr (Custom Success URL)}};\n  return (a && a.payment_method) ? a.payment_method : undefined;\n}"
          }
        ],
        "notes": "Custom thank-you page."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "34",
        "name": "TuriTop Custom - JS - URL site_url",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // site_url packed in tt_attr: origin + path of the page the booking started on.\n  // undefined when tt_attr is absent or invalid, or site_url is not a string.\n  var a = {{TuriTop Custom - JS - decode tt_attr (Custom Success URL)}};\n  return (a && typeof a.site_url === 'string' && a.site_url) ? a.site_url : undefined;\n}"
          }
        ],
        "notes": "Custom thank-you page."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "20",
        "name": "TuriTop Custom - JS - GA4 purchase already sent",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // true when this browser already sent this purchase to this destination: the tag\n  // 'TuriTop Custom - Mark GA4 purchase as sent' writes the key tt_purchase_ga4_{code} in localStorage.\n  // Without a code, or without localStorage, it returns false so that a purchase is never lost.\n  var id = {{TuriTop Custom - JS - URL transaction_id}};\n  if (!id) { return false; }\n  try {\n    return window.localStorage.getItem('tt_purchase_ga4_' + id) !== null;\n  } catch (e) { return false; }\n}"
          }
        ],
        "notes": "Custom thank-you page. Reload guard used by the exception 'TuriTop Custom - Block - GA4 purchase already sent'."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "33",
        "name": "TuriTop Custom - JS - Ads purchase already sent",
        "type": "jsm",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "javascript",
            "value": "function() {\n  // true when this browser already sent this purchase to this destination: the tag\n  // 'TuriTop Custom - Mark Google Ads purchase as sent' writes the key tt_purchase_ads_{code} in localStorage.\n  // Without a code, or without localStorage, it returns false so that a purchase is never lost.\n  var id = {{TuriTop Custom - JS - URL transaction_id}};\n  if (!id) { return false; }\n  try {\n    return window.localStorage.getItem('tt_purchase_ads_' + id) !== null;\n  } catch (e) { return false; }\n}"
          }
        ],
        "notes": "Custom thank-you page. Reload guard used by the exception 'TuriTop Custom - Block - Ads purchase already sent'."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "21",
        "name": "TuriTop Custom - URL - currency",
        "type": "u",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "component",
            "value": "QUERY"
          },
          {
            "type": "TEMPLATE",
            "key": "queryKey",
            "value": "currency"
          }
        ],
        "notes": "Custom thank-you page."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "22",
        "name": "TuriTop Custom - URL - product_short_id",
        "type": "u",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "component",
            "value": "QUERY"
          },
          {
            "type": "TEMPLATE",
            "key": "queryKey",
            "value": "product_short_id"
          }
        ],
        "notes": "Custom thank-you page."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "23",
        "name": "TuriTop Custom - URL - product_name",
        "type": "u",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "component",
            "value": "QUERY"
          },
          {
            "type": "TEMPLATE",
            "key": "queryKey",
            "value": "product_name"
          }
        ],
        "notes": "Custom thank-you page. Long URLs may drop it."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "24",
        "name": "TuriTop Custom - URL - csid",
        "type": "u",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "component",
            "value": "QUERY"
          },
          {
            "type": "TEMPLATE",
            "key": "queryKey",
            "value": "csid"
          }
        ],
        "notes": "Custom thank-you page. Company short_id (the provider in a resale)."
      },
      {
        "accountId": "0000000000",
        "containerId": "00000000",
        "variableId": "25",
        "name": "TuriTop Custom - URL - payment_link",
        "type": "u",
        "parameter": [
          {
            "type": "TEMPLATE",
            "key": "component",
            "value": "QUERY"
          },
          {
            "type": "TEMPLATE",
            "key": "queryKey",
            "value": "payment_link"
          }
        ],
        "notes": "Custom thank-you page. 1 = payment link: not a purchase, the trigger does not fire."
      }
    ]
  }
}
