Improve visitor bot filtering

This commit is contained in:
rajchales-monito
2026-07-30 13:46:39 +02:00
parent 349f42346e
commit d815fa6d0e
+26 -6
View File
@@ -1835,7 +1835,16 @@ function currentVisitors() {
function formatVisitorSession(row, thresholds = adminPresenceSettings()) { function formatVisitorSession(row, thresholds = adminPresenceSettings()) {
const history = parseJson(row.browsing_history_json, []); const history = parseJson(row.browsing_history_json, []);
const device = parseJson(row.device_json, {}); const device = parseJson(row.device_json, {});
const bot = botInfo(device.userAgent); const pageCountValue = new Set(history.map((item) => item.url).filter(Boolean)).size;
const sessionSecondsValue = sessionSeconds(row.browsing_history_json, row.first_seen_at);
const conversationCountValue = row.visitor_conversation_count || 0;
const bot = botInfo(device.userAgent, {
pageCount: pageCountValue,
visitCount: Math.max(1, history.length),
conversationCount: conversationCountValue,
sessionSeconds: sessionSecondsValue,
referrer: row.referrer
});
const countryCode = row.country_code || countryFromTimezone(row.timezone) || countryFromLanguage(row.language); const countryCode = row.country_code || countryFromTimezone(row.timezone) || countryFromLanguage(row.language);
const presence = visitorPresence(row, thresholds); const presence = visitorPresence(row, thresholds);
return { return {
@@ -1849,9 +1858,9 @@ function formatVisitorSession(row, thresholds = adminPresenceSettings()) {
currentUrl: row.current_url, currentUrl: row.current_url,
referrer: row.referrer, referrer: row.referrer,
browsingHistory: history, browsingHistory: history,
pageCount: new Set(history.map((item) => item.url).filter(Boolean)).size, pageCount: pageCountValue,
visitCount: Math.max(1, history.length), visitCount: Math.max(1, history.length),
conversationCount: row.visitor_conversation_count || 0, conversationCount: conversationCountValue,
lastConversationId: row.last_conversation_id, lastConversationId: row.last_conversation_id,
isBot: bot.isBot, isBot: bot.isBot,
botReason: bot.reason, botReason: bot.reason,
@@ -1860,7 +1869,7 @@ function formatVisitorSession(row, thresholds = adminPresenceSettings()) {
timezone: row.timezone, timezone: row.timezone,
countryCode, countryCode,
countryFlag: countryCode ? flagEmoji(countryCode) : "", countryFlag: countryCode ? flagEmoji(countryCode) : "",
sessionSeconds: sessionSeconds(row.browsing_history_json, row.first_seen_at), sessionSeconds: sessionSecondsValue,
firstSeenAt: row.first_seen_at, firstSeenAt: row.first_seen_at,
lastActivityAt: row.last_activity_at, lastActivityAt: row.last_activity_at,
lastSeenAt: row.last_seen_at lastSeenAt: row.last_seen_at
@@ -2245,19 +2254,30 @@ function countryFromLanguage(language) {
return match ? match[1].toUpperCase() : null; return match ? match[1].toUpperCase() : null;
} }
function botInfo(userAgent) { function botInfo(userAgent, activity = {}) {
const ua = String(userAgent || ""); const ua = String(userAgent || "");
const patterns = [ const patterns = [
"googlebot", "bingbot", "slurp", "duckduckbot", "baiduspider", "yandexbot", "googlebot", "bingbot", "slurp", "duckduckbot", "baiduspider", "yandexbot",
"ahrefsbot", "semrushbot", "mj12bot", "dotbot", "petalbot", "bytespider", "ahrefsbot", "semrushbot", "mj12bot", "dotbot", "petalbot", "bytespider",
"facebookexternalhit", "twitterbot", "linkedinbot", "slackbot", "discordbot", "facebookexternalhit", "twitterbot", "linkedinbot", "slackbot", "discordbot",
"whatsapp", "telegrambot", "preview", "crawler", "spider", "headlesschrome", "whatsapp", "telegrambot", "preview", "crawler", "spider", "headlesschrome",
"pingdom", "uptimerobot", "curl", "wget", "python-requests", "axios", "httpclient" "phantomjs", "playwright", "puppeteer", "selenium", "cypress", "chrome-lighthouse",
"pagespeed", "lighthouse", "pingdom", "uptimerobot", "curl", "wget",
"python-requests", "aiohttp", "go-http-client", "axios", "httpclient", "java/",
"okhttp", "libwww-perl", "scrapy", "httpx", "node-fetch", "undici"
]; ];
const lower = ua.toLowerCase(); const lower = ua.toLowerCase();
const match = patterns.find((pattern) => lower.includes(pattern)); const match = patterns.find((pattern) => lower.includes(pattern));
if (match) return { isBot: true, reason: match }; if (match) return { isBot: true, reason: match };
if (/\bbot\b/i.test(ua)) return { isBot: true, reason: "bot" }; if (/\bbot\b/i.test(ua)) return { isBot: true, reason: "bot" };
if (!ua.trim()) return { isBot: true, reason: "empty ua" };
if (activity.conversationCount > 0) return { isBot: false, reason: "" };
const pageCount = Number(activity.pageCount || 0);
const visitCount = Number(activity.visitCount || 0);
const sessionSecondsValue = Number(activity.sessionSeconds || 0);
if (pageCount >= 25 && sessionSecondsValue <= 180) return { isBot: true, reason: "fast crawler" };
if (pageCount >= 40) return { isBot: true, reason: "many pages" };
if (visitCount >= 60 && !activity.referrer) return { isBot: true, reason: "no-ref crawler" };
return { isBot: false, reason: "" }; return { isBot: false, reason: "" };
} }