PageSourceSearch

https://glycosutra.ai/assets/glyco-track.js?v=20260818-144

js glycosutra.ai collected 2026-10-05 15:17:44 UTC 10,022 bytes, 171 lines download raw bytes

1/* ════════════════════════════════════════════════════════════════════════════
2   Glycosutra — shared analytics + Google Ads conversion tracking
3
4   ┌────────────────────────────────────────────────────────────────────────┐
5   │  LAST UPDATED : 2026-08-18  22:10 IST   (delta-144)                     │
6   ├────────────────────────────────────────────────────────────────────────┤
7   │  2026-08-18  delta-144  captures gclid / utm_* so leads can be traced   │
8   │                         to a channel; strips query strings (cal.com was  │
9   │                         forwarding the booker's EMAIL in the URL).       │
10   │  2026-08-18  delta-143  chat.whatsapp.com group joins now fire          │
11   │                         whatsapp_group_join, and are NOT counted as an  │
12   │                         Ads conversion. A group join is not a lead.     │
13   │  2026-08-15  delta-140  created — GA4 + Ads conversion tracking; one    │
14   │                         file so the IDs cannot drift between pages.     │
15   └────────────────────────────────────────────────────────────────────────┘
16   ▸ WHEN YOU CHANGE THIS FILE, ADD A DATED LINE ABOVE.
17     Windows Explorer's "Date" column often shows Date *Created*, not Date
18     Modified, so it cannot be trusted to tell you whether the copy sitting on
19     Hostinger is current. This header is the source of truth.
20
21   ▸ PASTE YOUR THREE IDs BELOW. This is the ONLY file you need to edit —
22     every page (homepage + the db_reversal funnel) loads this one script, so
23     the IDs can never drift out of sync between pages.
24
25       GA4   : analytics.google.com › Admin › Data streams        -> G-XXXXXXXXXX
26       ADS   : ads.google.com › Goals › Conversions › Tag setup   -> AW-XXXXXXXXX
27       LABEL : the conversion action's label, e.g. "abcDEfghIJ"
28
29   Until real IDs are pasted, this file is INERT: no network request, no errors,
30   nothing breaks. Verify with tagassistant.google.com before spending ad budget.
31
32   Privacy: a health-adjacent site, so IP anonymisation is on, ad personalisation
33   is off, and ads_data_redaction is on. Lead name / email / phone are NEVER sent
34   to Google — only the fact that a conversion happened.
35   ════════════════════════════════════════════════════════════════════════════ */
36(function () {
37  'use strict';
38
39  var GA4   = 'G-SYLK1XYPY3';             // Glycosutra GA4 property (live 2026-08-15)
40  var ADS   = 'ADS_CONVERSION_ID';        // e.g. 'AW-XXXXXXXXX'
41  var LABEL = 'ADS_CONVERSION_LABEL';     // e.g. 'abcDEfghIJ'
42
43  var hasGA4 = GA4.indexOf('G-') === 0;
44  var hasAds = ADS.indexOf('AW-') === 0;
45  var hasLabel = LABEL.indexOf('ADS_') !== 0;
46  window.GLYCO_TRACKING_LIVE = hasGA4 || hasAds;
47
48  // ── attribution capture (delta-144) ──────────────────────────────────────
49  // Google puts ?gclid=... on the URL when someone arrives from an ad. It was
50  // already there and nothing read it, so every lead recorded its SOURCE as
51  // "db_reversal_funnel" — the page it was filled on, not where the person came
52  // from. Google Ads, Meta, a typed URL and a shared link all looked identical,
53  // which made cost-per-lead unknowable (₹270 or ₹450 depending on how many of
54  // the 5 leads on 2026-08-18 actually came from the ads).
55  //
56  // Captured on FIRST landing and kept in sessionStorage, because the visitor
57  // lands on index.html and submits from there — the parameters are gone from
58  // the URL by the time any later page loads.
59  var ATTR_KEYS = ['gclid','gbraid','wbraid','fbclid','msclkid',
60                   'utm_source','utm_medium','utm_campaign','utm_term','utm_content'];
61  var ATTR_STORE = 'glyco_attr';
62
63  function captureAttribution() {
64    var found = {}, qs, i, kv, k, v;
65    try {
66      qs = (window.location.search || '').replace(/^\?/, '').split('&');
67      for (i = 0; i < qs.length; i++) {
68        kv = qs[i].split('=');
69        k = decodeURIComponent(kv[0] || '');
70        v = decodeURIComponent((kv[1] || '')).slice(0, 200);
71        if (v && ATTR_KEYS.indexOf(k) > -1) found[k] = v;
72      }
73      if (Object.keys(found).length) {
74        found.landing_page = window.location.pathname;
75        found.referrer = (document.referrer || '').slice(0, 200);
76        sessionStorage.setItem(ATTR_STORE, JSON.stringify(found));
77      } else if (!sessionStorage.getItem(ATTR_STORE)) {
78        // no ad parameters — record the referrer so Direct vs Organic is still known
79        sessionStorage.setItem(ATTR_STORE, JSON.stringify({
80          referrer: (document.referrer || '').slice(0, 200),
81          landing_page: window.location.pathname
82        }));
83      }
84    } catch (e) { /* private mode / storage disabled — never break the page */ }
85  }
86
87  /** What the funnel form attaches to the lead. Always an object. */
88  window.glycoAttribution = function () {
89    try { return JSON.parse(sessionStorage.getItem(ATTR_STORE) || '{}'); }
90    catch (e) { return {}; }
91  };
92
93  captureAttribution();
94
95  window.dataLayer = window.dataLayer || [];
96  function gtag() { dataLayer.push(arguments); }
97  window.gtag = window.gtag || gtag;
98
99  if (window.GLYCO_TRACKING_LIVE) {
100    var el = document.createElement('script');
101    el.async = true;
102    el.src = 'https://www.googletagmanager.com/gtag/js?id=' + (hasGA4 ? GA4 : ADS);
103    document.head.appendChild(el);
104  }
105
106  gtag('js', new Date());
107  gtag('set', 'ads_data_redaction', true);
108  gtag('set', 'allow_ad_personalization_signals', false);
109  // delta-144 PII GUARD: cal.com was appending the booker's email to the
110  // thank-you URL (?email=...). page_location defaults to the full URL, which
111  // would have sent that email to Google — breaking this file's own promise
112  // above. Send the path only; query strings never leave the browser.
113  var CLEAN_LOCATION = window.location.origin + window.location.pathname;
114  if (hasGA4) gtag('config', GA4, {
115    anonymize_ip: true,
116    page_location: CLEAN_LOCATION
117  });
118  if (hasAds) gtag('config', ADS);
119
120  /** Fire an event; optionally also count it as a Google Ads conversion. */
121  function track(name, params, isConversion) {
122    try {
123      gtag('event', name, params || {});
124      if (isConversion && hasAds && hasLabel) {
125        gtag('event', 'conversion', { send_to: ADS + '/' + LABEL });
126      }
127    } catch (e) { /* analytics must never break the page */ }
128  }
129  window.glycoTrack = track;   // funnel pages call this on successful lead capture
130
131  // ── link conversions (homepage: 9x cal.com + WhatsApp) ────────────────────
132  // Delegated, so links added later are tracked with no further edits.
133  document.addEventListener('click', function (e) {
134    var a = e.target && e.target.closest ? e.target.closest('a[href]') : null;
135    if (!a) return;
136    var href = a.getAttribute('href') || '';
137    var label = (a.textContent || '').trim().slice(0, 60);
138    if (href.indexOf('cal.com') > -1)            track('book_consultation_click', { link_text: label }, true);
139    // delta-143: a GROUP JOIN is not a lead. chat.whatsapp.com is checked FIRST
140    // and reported as a non-conversion, otherwise it fell through to the
141    // wa.me branch below and would be counted as a Google Ads conversion —
142    // re-creating the exact over-counting that made the Ads dashboard claim
143    // 27 conversions against 5 real leads on 2026-08-18.
144    else if (href.indexOf('chat.whatsapp.com') > -1)
145                                                 track('whatsapp_group_join',     { link_text: label }, false);
146    else if (href.indexOf('wa.me') > -1 ||
147             href.indexOf('whatsapp') > -1)      track('whatsapp_click',          { link_text: label }, true);
148    else if (href.indexOf('tel:') === 0)         track('phone_click',             { link_text: label }, true);
149    else if (href.indexOf('mailto:') === 0)      track('email_click',             { link_text: label }, false);
150  }, true);
151
152  // ── engagement depth — separates real readers from bounced ad traffic ─────
153  var marks = [25, 50, 75, 90], fired = {};
154  window.addEventListener('scroll', function () {
155    var h = document.documentElement;
156    var pct = (h.scrollTop + window.innerHeight) / h.scrollHeight * 100;
157    for (var i = 0; i < marks.length; i++) {
158      var m = marks[i];
159      if (pct >= m && !fired[m]) { fired[m] = 1; track('scroll_depth', { percent: m }, false); }
160    }
161  }, { passive: true });
162
163  setTimeout(function () { track('engaged_45s', {}, false); }, 45000);
164
165  // ── funnel step auto-tagging ─────────────────────────────────────────────
166  // video.html and thank-you.html are steps AFTER the lead is captured, so
167  // reaching them is itself the signal worth measuring.
168  var path = (location.pathname || '').toLowerCase();
169  if (path.indexOf('thank-you') > -1)  track('funnel_thank_you', {}, false);
170  else if (path.indexOf('video') > -1) track('funnel_video_reached', {}, false);
171})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.