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()) {
const history = parseJson(row.browsing_history_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 presence = visitorPresence(row, thresholds);
return {
@@ -1849,9 +1858,9 @@ function formatVisitorSession(row, thresholds = adminPresenceSettings()) {
currentUrl: row.current_url,
referrer: row.referrer,
browsingHistory: history,
pageCount: new Set(history.map((item) => item.url).filter(Boolean)).size,
pageCount: pageCountValue,
visitCount: Math.max(1, history.length),
conversationCount: row.visitor_conversation_count || 0,
conversationCount: conversationCountValue,
lastConversationId: row.last_conversation_id,
isBot: bot.isBot,
botReason: bot.reason,
@@ -1860,7 +1869,7 @@ function formatVisitorSession(row, thresholds = adminPresenceSettings()) {
timezone: row.timezone,
countryCode,
countryFlag: countryCode ? flagEmoji(countryCode) : "",
sessionSeconds: sessionSeconds(row.browsing_history_json, row.first_seen_at),
sessionSeconds: sessionSecondsValue,
firstSeenAt: row.first_seen_at,
lastActivityAt: row.last_activity_at,
lastSeenAt: row.last_seen_at
@@ -2245,19 +2254,30 @@ function countryFromLanguage(language) {
return match ? match[1].toUpperCase() : null;
}
function botInfo(userAgent) {
function botInfo(userAgent, activity = {}) {
const ua = String(userAgent || "");
const patterns = [
"googlebot", "bingbot", "slurp", "duckduckbot", "baiduspider", "yandexbot",
"ahrefsbot", "semrushbot", "mj12bot", "dotbot", "petalbot", "bytespider",
"facebookexternalhit", "twitterbot", "linkedinbot", "slackbot", "discordbot",
"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 match = patterns.find((pattern) => lower.includes(pattern));
if (match) return { isBot: true, reason: match };
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: "" };
}