PageSourceSearch

https://buy.bangnbody.com/attribution.js?shop=bangn-body.myshopify.com

js bangnbody.com collected 2026-09-25 18:39:16 UTC 4,777 bytes, 171 lines download raw bytes

1(() => {
2  // Wide debug logging for staging/dev domains
3  var DEBUG = true;
4  var wideEvent = {
5    script: 'attribution.js',
6    hostname: location.hostname,
7    url: location.href,
8    debug: DEBUG
9  };
10
11  function emit(outcome) {
12    if (!DEBUG) return;
13    wideEvent.outcome = outcome;
14    wideEvent.duration_ms = Date.now() - wideEvent.start_time;
15    console.log('[GF Attribution]', JSON.stringify(wideEvent, null, 2));
16  }
17
18  wideEvent.start_time = Date.now();
19
20  // Bail out if running in a sandboxed iframe without cookie access
21  try {
22    var _ = document.cookie;
23  } catch (_e) {
24    wideEvent.sandboxed = true;
25    emit('sandboxed_exit');
26    return;
27  }
28
29  var el = document.currentScript || document.querySelector('[data-gf-subdomain], [data-gf-source="theme-app-embed"]');
30  // Extract context from data attributes or from the hosted script URL. Theme app extensions
31  // serve assets from Shopify CDN, so absence of a funnel subdomain should not block cart attribution.
32  var configuredSubdomain = el?.getAttribute('data-gf-subdomain');
33  var shopDomain = el?.getAttribute('data-gf-shop');
34  var isThemeAppEmbed = el?.getAttribute('data-gf-source') === 'theme-app-embed';
35  var scriptHost = null;
36  if (el?.src) {
37    try {
38      var srcHost = new URL(el.src).hostname;
39      if (srcHost && srcHost !== location.hostname) scriptHost = srcHost;
40    } catch (_e) {}
41  }
42  var subdomain = configuredSubdomain || scriptHost || null;
43  wideEvent.script_src = el ? el.src : null;
44  wideEvent.asset_host = scriptHost;
45  wideEvent.source = el?.getAttribute('data-gf-source') || null;
46  wideEvent.shop_domain = shopDomain;
47  wideEvent.subdomain = subdomain;
48  wideEvent.subdomain_source = configuredSubdomain ? 'data_attr' : scriptHost ? 'script_src' : 'none';
49  wideEvent.theme_app_embed = isThemeAppEmbed;
50  wideEvent.no_subdomain = !subdomain;
51
52  if (!subdomain && !isThemeAppEmbed) {
53    wideEvent.exit_reason = 'no_subdomain';
54    emit('no_subdomain');
55    return;
56  }
57
58  var TTL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
59
60  function getCookie(name) {
61    var match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
62    return match ? match[1] : null;
63  }
64
65  function payloadHash(p) {
66    return [p.pid, p.sid, p.fid, p.uid, p.vid, p.eid].join('|');
67  }
68
69  function alreadyApplied(p) {
70    try {
71      var applied = JSON.parse(localStorage.getItem('_gf_applied') || '{}');
72      return applied.hash === payloadHash(p);
73    } catch (_e) {
74      return false;
75    }
76  }
77
78  function markApplied(p) {
79    try {
80      localStorage.setItem('_gf_applied', JSON.stringify({ hash: payloadHash(p) }));
81    } catch (_e) {}
82  }
83
84  function updateCart(p) {
85    var body = { attributes: {} };
86    if (p.pid) body.attributes._gf_pid = p.pid;
87    if (p.sid) body.attributes._gf_sid = p.sid;
88    if (p.fid) body.attributes._gf_fid = p.fid;
89    if (p.uid) body.attributes._gf_uid = p.uid;
90    if (p.vid) body.attributes._gf_vid = p.vid;
91    if (p.eid) body.attributes._gf_eid = p.eid;
92    body.attributes._gf_src = 'indirect';
93
94    wideEvent.cart_attributes = body.attributes;
95
96    fetch('/cart/update.js', {
97      method: 'POST',
98      headers: { 'Content-Type': 'application/json' },
99      body: JSON.stringify(body)
100    })
101      .then((res) => {
102        wideEvent.cart_update_status = res.status;
103        markApplied(p);
104        emit('cart_updated');
105      })
106      .catch((err) => {
107        wideEvent.cart_update_error = String(err);
108        emit('cart_update_failed');
109      });
110  }
111
112  function apply(p) {
113    if (window.requestIdleCallback) {
114      requestIdleCallback(() => {
115        updateCart(p);
116      });
117    } else {
118      setTimeout(() => {
119        updateCart(p);
120      }, 0);
121    }
122  }
123
124  // Read attribution from cookie
125  try {
126    var allCookies = document.cookie;
127    wideEvent.cookie_count = (allCookies.match(/=/g) || []).length;
128    wideEvent.cookie_length = allCookies.length;
129
130    var raw = getCookie('_gf_attr');
131    wideEvent.has_gf_attr = !!raw;
132    wideEvent.gf_attr_raw = raw;
133
134    if (!raw) {
135      emit('no_cookie');
136      return;
137    }
138
139    var p = JSON.parse(decodeURIComponent(raw));
140    wideEvent.payload = p;
141    wideEvent.has_pid = !!p.pid;
142
143    if (!p || !p.pid) {
144      emit('no_pid');
145      return;
146    }
147
148    if (p.ts) {
149      var age_ms = Date.now() - p.ts;
150      wideEvent.cookie_age_ms = age_ms;
151      wideEvent.cookie_age_hours = Math.round(age_ms / 3600000);
152      if (age_ms > TTL_MS) {
153        emit('cookie_expired');
154        return;
155      }
156    }
157
158    var wasApplied = alreadyApplied(p);
159    wideEvent.already_applied = wasApplied;
160    if (wasApplied) {
161      emit('already_applied');
162      return;
163    }
164
165    emit('applying');
166    apply(p);
167  } catch (e) {
168    wideEvent.error = String(e);
169    emit('error');
170  }
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.