PageSourceSearch

https://calexitnow.com/analytics.js?v=66

js calexitnow.com collected 2026-10-10 02:25:08 UTC 4,622 bytes, 103 lines download raw bytes

1/* CalExitNow.com — analytics + funnel instrumentation (privacy-light, Umami).
2 *
3 * Self-hosted Umami, no cookies, no consent banner required.
4 * Set UMAMI_SRC + UMAMI_WEBSITE_ID below once the Umami instance is live and a
5 * "website" has been created in its dashboard. Until then this file runs
6 * harmlessly: UTM/attribution capture + funnel event wiring stay active and
7 * caTrack() is a safe no-op, so nothing breaks and no data leaks.
8 */
9(function () {
10  'use strict';
11
12  /* ===== CONFIG — fill these two when Umami is deployed ===== */
13  var UMAMI_SRC = '';         // e.g. 'https://analytics.calexitnow.com/script.js'
14  var UMAMI_WEBSITE_ID = '';  // e.g. '00000000-0000-0000-0000-000000000000'
15  /* ========================================================== */
16
17  // Load the Umami tracker only when configured.
18  if (UMAMI_SRC && UMAMI_WEBSITE_ID) {
19    var s = document.createElement('script');
20    s.defer = true;
21    s.src = UMAMI_SRC;
22    s.setAttribute('data-website-id', UMAMI_WEBSITE_ID);
23    document.head.appendChild(s);
24  }
25
26  // Event helper — no-op until Umami's global is present.
27  window.caTrack = function (name, props) {
28    try {
29      if (window.umami && typeof window.umami.track === 'function') {
30        window.umami.track(name, props || {});
31      }
32    } catch (e) { /* never break the page for analytics */ }
33  };
34
35  // ----- First-touch attribution (UTMs + referrer), persisted for the session -----
36  // 'ref' is the referral code from a supporter's share link. Captured
37  // first-touch alongside the UTMs so an invite still gets credit if the
38  // visitor wanders the site before signing up.
39  var UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'ref'];
40  function captureAttribution() {
41    try {
42      var sp = new URLSearchParams(location.search), got = {};
43      UTM_KEYS.forEach(function (k) { var v = sp.get(k); if (v) got[k] = v.slice(0, 120); });
44      if (Object.keys(got).length && !sessionStorage.getItem('ca_attr')) {
45        got.landing_path = location.pathname;
46        got.referrer = (document.referrer || '').slice(0, 200);
47        sessionStorage.setItem('ca_attr', JSON.stringify(got));
48      }
49    } catch (e) {}
50  }
51  window.caAttribution = function () {
52    try { return JSON.parse(sessionStorage.getItem('ca_attr') || '{}'); } catch (e) { return {}; }
53  };
54  captureAttribution();
55
56  document.addEventListener('DOMContentLoaded', function () {
57    var attr = window.caAttribution();
58
59    // Persist attribution into the signup form so it lands in the DB (raw JSON).
60    var form = document.querySelector('form[name="signup2"]');
61    if (form) {
62      Object.keys(attr).forEach(function (k) {
63        var existing = form.querySelector('[name="' + k + '"]');
64        if (existing) { existing.value = attr[k]; return; }
65        var i = document.createElement('input');
66        i.type = 'hidden'; i.name = k; i.value = attr[k];
67        form.appendChild(i);
68      });
69      // form_view: signup card scrolled into view (fires once).
70      var card = form.closest('.signup-card') || form;
71      if ('IntersectionObserver' in window) {
72        var io = new IntersectionObserver(function (ents) {
73          ents.forEach(function (en) { if (en.isIntersecting) { window.caTrack('form_view'); io.disconnect(); } });
74        }, { threshold: 0.5 });
75        io.observe(card);
76      }
77    }
78
79    // Delegated click tracking for the key funnel actions.
80    document.addEventListener('click', function (e) {
81      var el = e.target.closest('a, button');
82      if (!el) return;
83      var href = (el.getAttribute('href') || '').toLowerCase();
84      var label = (el.textContent || '').trim().slice(0, 60);
85      if (href.indexOf('/donate') > -1 || href.indexOf('donate@') > -1) {
86        window.caTrack('donate_click', { label: label });
87      } else if (href.indexOf('#signup') > -1 || /join the movement|count me in|get involved/i.test(label)) {
88        window.caTrack('cta_join_click', { label: label });
89      } else if (/tiktok|instagram|twitch|bsky|bluesky|youtube/.test(href)) {
90        window.caTrack('channel_click', { href: href });
91      } else if (el.classList && el.classList.contains('release-card')) {
92        window.caTrack('press_click', { href: el.getAttribute('href') || '' });
93      }
94    }, true);
95
96    // video_play: lite-youtube upgrades the facade on first activation.
97    document.querySelectorAll('lite-youtube').forEach(function (ly) {
98      ly.addEventListener('click', function () {
99        window.caTrack('video_play', { id: ly.getAttribute('videoid') || '' });
100      }, { once: true });
101    });
102  });
103})();

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.