Improve visitor bot filtering
This commit is contained in:
@@ -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: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user