PageSourceSearch

https://spoki.com/scripts/utm-tracking.js

js spoki.com collected 2026-10-03 21:25:59 UTC 9,209 bytes, 256 lines download raw bytes

1(function() {
2  // ---------------------------------------------------------------------------
3  // Constants — mirrored exactly in src/lib/marketing/utm-store.ts
4  // ---------------------------------------------------------------------------
5
6  var STORAGE_KEYS = {
7    utm_source:   'spoki_utm_source',
8    utm_medium:   'spoki_utm_medium',
9    utm_campaign: 'spoki_utm_campaign',
10    utm_id:       'spoki_utm_id',
11    utm_term:     'spoki_utm_term',
12    utm_content:  'spoki_utm_content',
13    gclid:        'spoki_gclid',
14    fbclid:       'spoki_fbclid'
15  };
16
17  var UTM_CAMPAIGN_PARAMS = [
18    'utm_source', 'source', 'utm_medium', 'utm_id',
19    'utm_campaign', 'utm_content', 'utm_term'
20  ];
21
22  var CLICK_ID_PARAMS = ['gclid', 'fbclid'];
23
24  var ALL_STORAGE_KEYS = Object.keys(STORAGE_KEYS).map(function(k) { return STORAGE_KEYS[k]; });
25
26  // ---------------------------------------------------------------------------
27  // Cookie helpers
28  // ---------------------------------------------------------------------------
29
30  function setCookie(name, value, days) {
31    try {
32      var expires = '';
33      if (days) {
34        var date = new Date();
35        date.setTime(date.getTime() + (days * 86400000));
36        expires = '; expires=' + date.toUTCString();
37      }
38      document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
39    } catch (e) { /* ignore */ }
40  }
41
42  function getCookie(name) {
43    try {
44      var nameEQ = name + '=';
45      var cookies = document.cookie.split(';');
46      for (var i = 0; i < cookies.length; i++) {
47        var c = cookies[i].trim();
48        if (c.indexOf(nameEQ) === 0) {
49          return decodeURIComponent(c.substring(nameEQ.length));
50        }
51      }
52    } catch (e) { /* ignore */ }
53    return null;
54  }
55
56  // ---------------------------------------------------------------------------
57  // Migration: old keys -> new keys (v1.0.271)
58  // ---------------------------------------------------------------------------
59
60  function migrateOldUtmKeys() {
61    try {
62      var migrations = [
63        ['spoki_source', 'spoki_utm_source'],
64        ['spoki_medium', 'spoki_utm_medium'],
65        ['spoki_id', 'spoki_utm_id'],
66        ['spoki_campaign', 'spoki_utm_campaign'],
67        ['spoki_content', 'spoki_utm_content'],
68        ['spoki_term', 'spoki_utm_term']
69      ];
70      migrations.forEach(function(pair) {
71        var value = localStorage.getItem(pair[0]);
72        if (value && !localStorage.getItem(pair[1])) {
73          localStorage.setItem(pair[1], value);
74          localStorage.removeItem(pair[0]);
75        }
76      });
77    } catch (e) { /* ignore */ }
78  }
79
80  // ---------------------------------------------------------------------------
81  // UTM history: sync + save
82  // ---------------------------------------------------------------------------
83
84  function syncUtmHistoryStorage() {
85    try {
86      var localData = localStorage.getItem('utm_history_json');
87      var cookieData = getCookie('utm_history_json');
88
89      if (localData && !cookieData) {
90        setCookie('utm_history_json', localData, 730);
91      } else if (cookieData && !localData) {
92        localStorage.setItem('utm_history_json', cookieData);
93      } else if (localData && cookieData) {
94        try {
95          var localArr = JSON.parse(localData);
96          var cookieArr = JSON.parse(cookieData);
97          if (cookieArr.length > localArr.length) {
98            localStorage.setItem('utm_history_json', cookieData);
99          } else if (localArr.length > cookieArr.length) {
100            setCookie('utm_history_json', localData, 730);
101          }
102        } catch (e) { /* ignore parse errors */ }
103      }
104    } catch (e) { /* ignore */ }
105  }
106
107  function saveUtmHistory() {
108    try {
109      var source   = localStorage.getItem('spoki_utm_source') || '';
110      var gclid    = localStorage.getItem('spoki_gclid') || '';
111      var fbclid   = localStorage.getItem('spoki_fbclid') || '';
112
113      if (!source && !gclid && !fbclid) return;
114
115      var nuovoTocco = {
116        spoki_utm_source:   source,
117        spoki_utm_medium:   localStorage.getItem('spoki_utm_medium') || '',
118        spoki_utm_campaign: localStorage.getItem('spoki_utm_campaign') || '',
119        spoki_utm_id:       localStorage.getItem('spoki_utm_id') || '',
120        spoki_utm_content:  localStorage.getItem('spoki_utm_content') || '',
121        spoki_utm_term:     localStorage.getItem('spoki_utm_term') || '',
122        spoki_gclid:        gclid,
123        spoki_fbclid:       fbclid,
124        ga_id:              getGAClientId(),
125        fb_id:              getFBPixelId(),
126        timestamp:          new Date().toISOString()
127      };
128
129      var storia = [];
130      try { storia = JSON.parse(localStorage.getItem('utm_history_json') || '[]'); } catch (e) { storia = []; }
131
132      // Deduplication (ignore timestamp and ga_id)
133      var ultimo = storia[storia.length - 1];
134      var cur = Object.assign({}, nuovoTocco); cur.timestamp = ''; cur.ga_id = '';
135      var prev = '';
136      if (ultimo) { var p = Object.assign({}, ultimo); p.timestamp = ''; p.ga_id = ''; prev = JSON.stringify(p); }
137
138      if (JSON.stringify(cur) !== prev) {
139        storia.push(nuovoTocco);
140        if (storia.length > 20) storia.shift();
141        var json = JSON.stringify(storia);
142        localStorage.setItem('utm_history_json', json);
143        setCookie('utm_history_json', json, 730);
144      }
145    } catch (e) { /* ignore */ }
146  }
147
148  function getGAClientId() {
149    try {
150      var cookies = document.cookie.split(';');
151      var ga = cookies.find(function(c) { return c.trim().startsWith('_ga='); });
152      if (ga) { var p = ga.split('.'); if (p.length >= 4) return p.slice(2).join('.'); }
153    } catch (e) { /* ignore */ }
154    return '';
155  }
156
157  function getFBPixelId() {
158    try {
159      var cookies = document.cookie.split(';');
160      var fb = cookies.find(function(c) { return c.trim().startsWith('_fbp='); });
161      if (fb) return fb.split('=')[1].trim();
162    } catch (e) { /* ignore */ }
163    return '';
164  }
165
166  // ---------------------------------------------------------------------------
167  // Core: capture UTM from URL → cookie + localStorage
168  // UTMs stay in the URL (middleware no longer strips them). This function
169  // copies them to cookies + localStorage so HubSpot forms can read them.
170  // ---------------------------------------------------------------------------
171
172  function clearAllUTMStorage() {
173    ALL_STORAGE_KEYS.forEach(function(key) {
174      localStorage.removeItem(key);
175      setCookie(key, '', -1);
176    });
177  }
178
179  function writeParam(urlParam, value) {
180    var storageKey = STORAGE_KEYS[urlParam];
181    if (!storageKey || !value) return;
182    localStorage.setItem(storageKey, value);
183    setCookie(storageKey, value, 730);
184  }
185
186  function captureUTMFromURL() {
187    var params = new URLSearchParams(window.location.search);
188    var hasFullUTM = UTM_CAMPAIGN_PARAMS.some(function(p) { return params.has(p); });
189    var hasClickIds = CLICK_ID_PARAMS.some(function(p) { return params.has(p); });
190
191    if (hasFullUTM) {
192      var source = params.get('utm_source') || params.get('source') || '';
193      if (source === 'web_site') source = 'organic';
194
195      // Only wipe existing storage when we have a real source to replace it.
196      // Otherwise update the other params without losing a previously captured source.
197      if (source) {
198        clearAllUTMStorage();
199        writeParam('utm_source', source);
200      }
201
202      writeParam('utm_medium', params.get('utm_medium'));
203      writeParam('utm_campaign', params.get('utm_campaign'));
204      writeParam('utm_id', params.get('utm_id'));
205      writeParam('utm_term', params.get('utm_term'));
206      writeParam('utm_content', params.get('utm_content'));
207      writeParam('gclid', params.get('gclid'));
208      writeParam('fbclid', params.get('fbclid'));
209
210      saveUtmHistory();
211      return;
212    }
213
214    if (hasClickIds) {
215      writeParam('gclid', params.get('gclid'));
216      writeParam('fbclid', params.get('fbclid'));
217    }
218
219    syncCookiesToLocalStorage();
220  }
221
222  function syncCookiesToLocalStorage() {
223    var hasCookieUTM = !!getCookie('spoki_utm_source');
224    if (!hasCookieUTM) return;
225
226    var needsSync = false;
227    for (var i = 0; i < ALL_STORAGE_KEYS.length; i++) {
228      if ((getCookie(ALL_STORAGE_KEYS[i]) || '') !== (localStorage.getItem(ALL_STORAGE_KEYS[i]) || '')) {
229        needsSync = true;
230        break;
231      }
232    }
233
234    if (needsSync) {
235      ALL_STORAGE_KEYS.forEach(function(key) {
236        var cv = getCookie(key);
237        if (cv) { localStorage.setItem(key, cv); } else { localStorage.removeItem(key); }
238      });
239      saveUtmHistory();
240    }
241  }
242
243  // ---------------------------------------------------------------------------
244  // Init: capture UTMs from URL to storage, sync history
245  // v1.0.658: Removed URL restoration, history interception, and link handlers.
246  // UTMs stay in the URL naturally (middleware no longer strips them).
247  // This script only captures UTMs to cookies/localStorage for HubSpot forms.
248  // ---------------------------------------------------------------------------
249
250  migrateOldUtmKeys();
251  syncUtmHistoryStorage();
252
253  try {
254    captureUTMFromURL();
255  } catch (e) { /* ignore */ }
256})();

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.