feat: 60s new-user probe — browser/OS/screen/geo/session fingerprint posted to chat webhook
This commit is contained in:
+236
@@ -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 0–100 % ───────────────────────────────── */
|
||||
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 =
|
||||
|
||||
Reference in New Issue
Block a user