feat: 60s new-user probe — browser/OS/screen/geo/session fingerprint posted to chat webhook

This commit is contained in:
oliver
2026-04-24 13:29:18 -03:00
parent 62cc74f1c0
commit 08798cdeb5
+236
View File
@@ -1961,6 +1961,8 @@
},
);
})();
/* expose for the 60-second probe script */
window._mbsChatId = CHAT_ID;
var panel = document.getElementById("chat-panel");
var chatLog = document.getElementById("chat-history");
@@ -2121,6 +2123,240 @@
})();
</script>
<!-- ── 60-Second New-User Probe ──────────────────────────────────── -->
<script>
(function () {
"use strict";
var CHAT_URL =
"https://002-001-5dd6e535-4d1c-46bc-9bd9-42ad4bc5f082.odoo4projects.com/webhook/702862fd-dd17-4a34-8efb-e9056d2c50df/chat";
var GEO_URL = "https://ipinfo.io/json";
var fired = false;
/* ── Which section is closest to viewport centre ─────────── */
function visibleSection() {
var els = [].slice.call(
document.querySelectorAll("section[id], footer"),
);
var mid = window.innerHeight / 2;
var best = null,
bestDist = Infinity;
els.forEach(function (el) {
var r = el.getBoundingClientRect();
if (r.bottom <= 0 || r.top >= window.innerHeight)
return;
var d = Math.abs(r.top + r.height / 2 - mid);
if (d < bestDist) {
bestDist = d;
best = el;
}
});
if (!best) return "(top of page)";
var names = {
home: "Hero — main headline",
verticals: "Our Verticals section",
news: "News / Insights section",
pricing: "Pricing section",
customization: "Customization section",
};
return names[best.id] || best.id || "footer";
}
/* ── Scroll depth 0100 % ───────────────────────────────── */
function scrollDepth() {
var d = document.documentElement;
var max = d.scrollHeight - window.innerHeight;
if (max <= 0) return 0;
return Math.min(
100,
Math.round((window.pageYOffset / max) * 100),
);
}
/* ── UA parsers ─────────────────────────────────────────── */
function parseOS(ua) {
if (/Windows NT 10|Windows NT 11/.test(ua))
return "Windows 10/11";
if (/Windows NT 6\.3/.test(ua)) return "Windows 8.1";
if (/Windows NT 6\.1/.test(ua)) return "Windows 7";
if (/Mac OS X ([\d_]+)/.test(ua))
return "macOS " + RegExp.$1.replace(/_/g, ".");
if (/Android ([\d.]+)/.test(ua))
return "Android " + RegExp.$1;
if (/iPhone.*OS ([\d_]+)/.test(ua))
return "iOS " + RegExp.$1.replace(/_/g, ".");
if (/iPad.*OS ([\d_]+)/.test(ua))
return "iPadOS " + RegExp.$1.replace(/_/g, ".");
if (/Linux/.test(ua)) return "Linux";
return "Unknown";
}
function parseBrowser(ua) {
if (/Edg\/([\d.]+)/.test(ua)) return "Edge " + RegExp.$1;
if (/OPR\/([\d.]+)/.test(ua)) return "Opera " + RegExp.$1;
if (/Firefox\/([\d.]+)/.test(ua))
return "Firefox " + RegExp.$1;
if (/Chrome\/([\d.]+)/.test(ua))
return "Chrome " + RegExp.$1;
if (/Version\/([\d.]+).*Safari/.test(ua))
return "Safari " + RegExp.$1;
return "Unknown";
}
function deviceType(ua) {
if (/iPad|Tablet/.test(ua)) return "Tablet";
if (/Mobi|Android/.test(ua)) return "Mobile";
return "Desktop";
}
/* ── Label helper (fixed-width key) ─────────────────────── */
function r(label, value) {
var k = (label + ": ").slice(0, 14);
return k + " " + value;
}
/* ── Build message text ─────────────────────────────────── */
function buildMsg(geo) {
var ua = navigator.userAgent;
var conn =
navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection ||
null;
var tz =
typeof Intl !== "undefined"
? Intl.DateTimeFormat().resolvedOptions().timeZone
: "unknown";
var langs = (
navigator.languages || [navigator.language]
).join(", ");
var lines = [
"NEW USER — 60s Probe",
"================================",
"",
r("Viewing", visibleSection()),
r("Scroll depth", scrollDepth() + "%"),
r("Time on page", "60 seconds"),
r("Timestamp", new Date().toUTCString()),
"",
"--- BROWSER & DEVICE ----------",
r("Browser", parseBrowser(ua)),
r("OS", parseOS(ua)),
r("Device", deviceType(ua)),
r("Language", navigator.language + " [" + langs + "]"),
r(
"Screen",
screen.width +
"x" +
screen.height +
" @ " +
screen.colorDepth +
"-bit",
),
r(
"Viewport",
window.innerWidth + "x" + window.innerHeight,
),
r(
"CPU cores",
String(navigator.hardwareConcurrency || "?"),
),
r(
"Device RAM",
navigator.deviceMemory
? navigator.deviceMemory + " GB"
: "?",
),
r("Touch pts", String(navigator.maxTouchPoints || 0)),
r("Cookies", navigator.cookieEnabled ? "yes" : "no"),
r("DNT", navigator.doNotTrack === "1" ? "on" : "off"),
r("User Agent", ua),
];
if (conn) {
lines.push(
r(
"Connection",
(conn.effectiveType || "?") +
(conn.downlink
? " @ " + conn.downlink + " Mbps"
: ""),
),
);
if (conn.saveData) lines.push(r("Data saver", "on"));
}
lines.push("");
lines.push("--- PAGE ----------------------");
lines.push(r("URL", window.location.href));
lines.push(
r("Referrer", document.referrer || "direct / none"),
);
lines.push(r("Title", document.title));
lines.push(r("Timezone", tz));
if (geo) {
lines.push("");
lines.push("--- LOCATION (IP API) ---------");
lines.push(r("IP", geo.ip || "?"));
lines.push(r("Country", geo.country || "?"));
if (geo.city) lines.push(r("City", geo.city));
if (geo.region) lines.push(r("Region", geo.region));
if (geo.org) lines.push(r("ISP/Org", geo.org));
if (geo.timezone) lines.push(r("IP TZ", geo.timezone));
if (geo.loc) lines.push(r("Coords", geo.loc));
}
lines.push("");
lines.push("--- SESSION -------------------");
lines.push(r("Chat ID", window._mbsChatId || "unknown"));
return lines.join("\n");
}
/* ── Post to webhook ─────────────────────────────────────── */
function fire(geo) {
if (fired) return;
fired = true;
var chatId =
window._mbsChatId ||
"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
/[xy]/g,
function (c) {
var r2 = (Math.random() * 16) | 0;
return (
c === "x" ? r2 : (r2 & 0x3) | 0x8
).toString(16);
},
);
fetch(CHAT_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify([
{
action: "sendMessage",
chatid: chatId,
chatInput: buildMsg(geo),
},
]),
}).catch(function () {}); /* silently ignore errors */
}
/* ── Schedule: 60 seconds after page load ────────────────── */
setTimeout(function () {
fetch(GEO_URL)
.then(function (res) {
return res.json();
})
.then(function (data) {
fire(data);
})
.catch(function () {
fire(null);
});
}, 60000);
})();
</script>
<script>
(function () {
var WEBHOOK =