Skip to content

Instantly share code, notes, and snippets.

@ceaksan
Created April 14, 2026 16:39
Show Gist options
  • Select an option

  • Save ceaksan/e3708eda7d73bc9a0b0fd5e8935a5549 to your computer and use it in GitHub Desktop.

Select an option

Save ceaksan/e3708eda7d73bc9a0b0fd5e8935a5549 to your computer and use it in GitHub Desktop.
GTM Custom HTML Tag: Send purchase event data + first-party cookie attribution (dnm_src/dnm_cid) to Umami via umami.track(). Cookie-less attribution debugging alongside GA4.
/**
* GTM Custom HTML Tag — Umami purchase event bridge
* File: gtm-umami-purchase-bridge.js
*
* What it does:
* Sends purchase event data + first-party cookie attribution
* to Umami via umami.track(). Runs alongside GA4 purchase tag
* to create an independent, cookie-less attribution record.
*
* Parameters sent to Umami:
* transaction_id → e.g. "ORD-2026-1234"
* value → e.g. 1250.00
* currency → e.g. "TRY"
* ft_source → e.g. "google" (from dnm_src cookie)
* ft_medium → e.g. "cpc" (from dnm_src cookie)
* ft_campaign → e.g. "TR_branded" (from dnm_src cookie)
* ft_click_id → e.g. "gclid:Cj0K..." (from dnm_cid cookie)
*
* Requires:
* - Umami script loaded on page (umami.track must be available)
* - storageHelper (see companion gist) loaded BEFORE this tag
* - ecommerce dataLayer push with transaction_id, value, currency
*
* Trigger:
* Purchase event trigger (same as GA4 purchase tag).
* Tag Sequencing: after storageHelper.
* Consent condition: analytics_storage = granted.
*
* Fails silently if Umami script is blocked (ad blocker)
* or not yet loaded.
*/
(function () {
if (typeof umami === "undefined" || typeof umami.track !== "function") {
return;
}
/* --- 1. Read ecommerce data from dataLayer ---------------------- */
var dl = window.dataLayer || [];
var ecomm = null;
for (var i = dl.length - 1; i >= 0; i--) {
if (dl[i].ecommerce && dl[i].ecommerce.transaction_id) {
ecomm = dl[i].ecommerce;
break;
}
}
var transactionId = ecomm ? String(ecomm.transaction_id) : "";
var value = ecomm ? Number(ecomm.value) || 0 : 0;
var currency = ecomm ? String(ecomm.currency || "TRY") : "TRY";
/* --- 2. Read first-party cookie attribution --------------------- */
var rawSource = storageHelper.get("dnm_src");
var rawCid = storageHelper.get("dnm_cid");
var parts = rawSource ? String(rawSource).split("|") : [];
var ftSource = parts[0] || "(not set)";
var ftMedium = parts[1] || "(not set)";
var ftCampaign = parts[2] || "(not set)";
var ftClickId = rawCid ? String(rawCid) : "(not set)";
/* --- 3. Send to Umami ------------------------------------------- */
umami.track("purchase", {
transaction_id: transactionId,
value: value,
currency: currency,
ft_source: ftSource,
ft_medium: ftMedium,
ft_campaign: ftCampaign,
ft_click_id: ftClickId,
});
/* --- 4. Debug log ----------------------------------------------- */
if (window.location.search.indexOf("dnm_debug=1") !== -1) {
console.group("[DNM] Umami purchase bridge");
console.log("transaction_id :", transactionId);
console.log("value :", value, currency);
console.log("ft_source :", ftSource);
console.log("ft_medium :", ftMedium);
console.log("ft_campaign :", ftCampaign);
console.log("ft_click_id :", ftClickId);
console.groupEnd();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment