Created
April 17, 2026 20:39
-
-
Save ceaksan/6d9db87a225cb5595dd5491d68df52aa to your computer and use it in GitHub Desktop.
Cart Abandonment Beacon Client - navigator.sendBeacon heartbeat client for server-side cart abandonment detection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Cart Abandonment - Beacon Client | |
| * | |
| * Server-side cart abandonment detector (client half). Emits beacons | |
| * for page_enter, periodic heartbeat, tab_hidden, tab_visible and | |
| * purchase_complete events so that a backend can decide abandonment | |
| * based on heartbeat silence (e.g. 30 minutes without heartbeat + | |
| * no purchase => abandonment). | |
| * | |
| * Pairs with the server-side handler: | |
| * https://gist.github.com/ceaksan/cart_abandonment_beacon_server.py | |
| * | |
| * Install via: GTM Custom HTML tag, trigger = All Pages / DOM Ready. | |
| * | |
| * @see https://ceaksan.com/tr/sepet-terk-takibi-javascript | |
| * @license MIT | |
| */ | |
| (function () { | |
| var ENDPOINT = "https://analytics.yoursite.com/cart-beacon"; | |
| var HEARTBEAT_MS = 10000; | |
| var sessionId = sessionStorage.getItem("beacon_session"); | |
| if (!sessionId) { | |
| sessionId = | |
| "sess_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); | |
| sessionStorage.setItem("beacon_session", sessionId); | |
| } | |
| var path = window.location.pathname; | |
| var isCartOrCheckout = /\/(sepet|cart|odeme|checkout)/i.test(path); | |
| var isOrderSuccess = /\/(siparis-sonuc|thank[-_]?you)/i.test(path); | |
| function sendBeacon(eventType) { | |
| var data = JSON.stringify({ | |
| eventType: eventType, | |
| sessionId: sessionId, | |
| url: window.location.href, | |
| timestamp: new Date().toISOString(), | |
| cartValue: extractCartValue(), | |
| }); | |
| if (navigator.sendBeacon) { | |
| navigator.sendBeacon( | |
| ENDPOINT, | |
| new Blob([data], { type: "application/json" }), | |
| ); | |
| } | |
| } | |
| function extractCartValue() { | |
| if (window.dataLayer) { | |
| for (var i = window.dataLayer.length - 1; i >= 0; i--) { | |
| var item = window.dataLayer[i]; | |
| if (item.ecommerce && item.ecommerce.value) { | |
| return item.ecommerce.value; | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| // Order success: cancel pending abandonment | |
| if (isOrderSuccess) { | |
| sendBeacon("purchase_complete"); | |
| return; | |
| } | |
| // Only run on cart and checkout pages | |
| if (!isCartOrCheckout) return; | |
| // Page enter beacon | |
| sendBeacon("page_enter"); | |
| // Heartbeat: active signal every 10s | |
| var heartbeatInterval = setInterval(function () { | |
| sendBeacon("heartbeat"); | |
| }, HEARTBEAT_MS); | |
| // Tab hidden beacon (mobile-reliable) | |
| document.addEventListener("visibilitychange", function () { | |
| if (document.visibilityState === "hidden") { | |
| sendBeacon("tab_hidden"); | |
| clearInterval(heartbeatInterval); | |
| } else if (document.visibilityState === "visible") { | |
| sendBeacon("tab_visible"); | |
| heartbeatInterval = setInterval(function () { | |
| sendBeacon("heartbeat"); | |
| }, HEARTBEAT_MS); | |
| } | |
| }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment