PageSourceSearch

https://bati.ai/batioffice/tracking.js

js bati.ai collected 2026-10-01 15:40:30 UTC 4,071 bytes, 103 lines download raw bytes

1(function () {
2  "use strict";
3
4  var beaconUrl = "https://os-api.bati.ai/api/public/analytics/beacon";
5  var storageKey = "__a_fp";
6  var isPublicBatiHost = /(^|\.)bati\.ai$/i.test(window.location.hostname);
7  var clicksBound = false;
8
9  function getFingerprint() {
10    var existing = "";
11    try {
12      existing = sessionStorage.getItem(storageKey) || "";
13    } catch (_) {
14      // Storage can be blocked in private or hardened browser contexts.
15    }
16    if (existing) return existing;
17
18    var fingerprint =
19      typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
20        ? crypto.randomUUID()
21        : "r-" + Math.random().toString(36).slice(2) + "-" + Date.now().toString(36);
22    try {
23      sessionStorage.setItem(storageKey, fingerprint);
24    } catch (_) {
25      // Analytics is intentionally best-effort.
26    }
27    return fingerprint;
28  }
29
30  var fingerprint = getFingerprint();
31
32  /*
33   * 어느 사이트로 집계할지.
34   *
35   * 이 스크립트는 bati.ai 전체가 쓴다(루트 · /about-us/ · /batioffice/). 지금까지 전부
36   * "landing" 으로 보냈는데, admin-os 의 그 항목은 **bati.so** 라벨이라 다른 도메인
37   * 숫자와 섞여 있었다. BatiOffice 유입이 얼마인지 볼 수가 없었던 이유다.
38   *
39   * /batioffice/ 만 따로 뗀다. 나머지(루트·about-us)가 여전히 bati.so 와 섞이는 것은
40   * 별건으로 남는다 — 여기서 한꺼번에 바꾸면 기존 집계가 끊긴다.
41   */
42  function resolveSite() {
43    return /^\/batioffice(\/|$)/i.test(window.location.pathname) ? "batioffice" : "landing";
44  }
45
46  function send(eventType, eventName, locale) {
47    var payload = {
48      site: resolveSite(),
49      // 서버 스키마가 page 를 /^\/[a-z0-9-\/]*$/ 로 제한한다. 대문자나 그 밖의 문자가
50      // 있으면 통째로 거부되는데 응답이 204 라 조용히 사라진다 — 여기서 맞춰 보낸다.
51      page: window.location.pathname.toLowerCase().replace(/[^a-z0-9\-/]/g, "").slice(0, 255) || "/",
52      eventType: eventType,
53      fingerprint: fingerprint,
54    };
55    if (eventName) payload.eventName = eventName;
56
57    window.dataLayer = window.dataLayer || [];
58    window.dataLayer.push({
59      event: eventName || "batioffice_landing_view",
60      event_type: eventType,
61      page_path: window.location.pathname,
62      page_locale: locale || document.documentElement.lang || "ko",
63    });
64
65    // dataLayer 만으로는 GA4 에 이벤트가 들어가지 않는다 — 이 사이트는 GTM 컨테이너가 아니라
66    // gtag.js 를 직접 싣기 때문이다(index.html 의 gtag('config', ...)). 그래서 다운로드·데모탭·
67    // 언어전환 같은 전환 이벤트가 하나도 기록되지 않고 page_view 만 남았다.
68    // dataLayer.push 는 향후 GTM 도입 대비로 그대로 둔다.
69    if (typeof window.gtag === "function") {
70      window.gtag("event", eventName || "batioffice_landing_view", {
71        event_type: eventType,
72        page_path: window.location.pathname,
73        page_locale: locale || document.documentElement.lang || "ko",
74      });
75    }
76
77    if (!isPublicBatiHost || !navigator.sendBeacon) return;
78    try {
79      navigator.sendBeacon(beaconUrl, new Blob([JSON.stringify(payload)], {
80        type: "text/plain;charset=UTF-8",
81      }));
82    } catch (_) {
83      // Tracking must never block a navigation or product download.
84    }
85  }
86
87  function bindTrackedClicks(locale) {
88    if (clicksBound) return;
89    clicksBound = true;
90    document.addEventListener("click", function (event) {
91      var target = event.target.closest("[data-track]");
92      var eventName = target && target.dataset.track;
93      if (target && target.getAttribute("aria-disabled") === "true") return;
94      if (!eventName || !/^batioffice_[a-z0-9_]+$/.test(eventName)) return;
95      send("click", eventName, locale);
96    }, true);
97  }
98
99  window.BatiLandingAnalytics = Object.freeze({
100    trackPageView: function (locale) { send("pageview", "", locale); },
101    bindTrackedClicks: bindTrackedClicks,
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.