filtering-bot-traffic

Par posthog · skills

Identifiez, mesurez et excluez le trafic de bots, de crawlers et d'agents IA dans les analyses web et produit PostHog en utilisant la surface de classification du trafic (les fonctions HogQL `isLikelyBot` / `getTrafficType` et les propriétés virtuelles `$virt_*`). À utiliser lorsque l'utilisateur souhaite « exclure les bots », « filtrer les crawlers », « supprimer le trafic de bots de mes chiffres », « quelle part de mon trafic provient de bots / crawlers IA », « est-ce que GPTBot / ChatGPT / Claude visite mon site », « ventiler le trafic par humains vs bots », ou veut des comptages uniquement humains dans une insight ou un dashboard. Pour les tuiles de bots de l'onglet Live en temps réel, utilisez plutôt `exploring-live-traffic`.

npx skills add https://github.com/posthog/skills --skill filtering-bot-traffic

Filtrer et mesurer le trafic des bots

PostHog classe chaque requête par user agent, ce qui te permet de distinguer les humains des bots, crawlers et agents IA partout où HogQL s'exécute — l'éditeur SQL, insights, tendances et Web analytics breakdowns. Cette skill t'apprend (l'agent) comment utiliser cette classification pour :

  • exclure les bots afin que l'analytics reflète uniquement le trafic humain
  • mesurer le volume de trafic automatisé et identifier les bots/opérateurs responsables
  • séparer le trafic des agents IA (intéressant à mesurer) du bruit (à ignorer)
  • choisir la bonne surface — virtual properties pour le insight builder, fonctions pour du SQL brut

Pour les questions sur les bots en temps réel (« maintenant », dernières 30 min) et les tuiles Live tab, utilise plutôt la skill exploring-live-traffic. Cette skill concerne les fenêtres historiques, insights sauvegardés, dashboards et filtrage.

Quand utiliser cette skill

Utilise-la quand l'utilisateur veut :

  • exclure ou filtrer les bots (« supprimer les bots de mes pageviews », « humains uniquement »)
  • quantifier le trafic automatisé (« quel % du trafic sont des bots ? », « combien de crawlers IA ? »)
  • identifier les bots qui les visitent (« quels crawlers nous visitent ? », « est-ce que ChatGPT lit notre documentation ? »)
  • diviser une tendance par type de trafic ou nom de bot
  • mesurer spécifiquement le trafic des agents IA / moteurs de recherche IA (AEO / answer-engine visibility)

Ne l'utilise pas pour le Live tab, les nombres en temps réel ou les graphiques de bots par minute — c'est le rôle de exploring-live-traffic.

La surface de classification

Deux façons équivalentes d'accéder à la même classification. Préfère les virtual properties dans le insight builder et les filtres ; utilise les fonctions dans du SQL manuscrit ou quand tu as besoin d'une valeur que les virtual properties n'exposent pas.

Virtual properties (insight builder, filtres, breakdowns)

Elles lisent le user agent pour toi (en revenant de $raw_user_agent à $user_agent), tu n'as donc rien à passer. Disponibles partout où tu sélectionnes une event property.

Property Value
$virt_is_bot boolean — true pour les bots / crawlers / automation
$virt_traffic_type Regular, AI Agent, Bot, ou Automation
$virt_traffic_category catégorie plus fine, ex. ai_crawler, ai_search, ai_assistant, search_crawler, seo_crawler, social_crawler, monitoring, http_client, headless_browser, no_user_agent, regular
$virt_bot_name nom d'affichage, ex. Googlebot, GPTBot, ClaudeBot
$virt_bot_operator entreprise derrière le bot, ex. Google, OpenAI, Anthropic

HogQL functions (SQL brut)

Passe le user agent explicitement. Utilise coalesce(nullIf(properties.$raw_user_agent, ''), properties.$user_agent) pour couvrir à la fois les captures côté serveur ($raw_user_agent) et SDK JS ($user_agent). Le nullIf empêche un $raw_user_agent vide de masquer un vrai $user_agent et d'être mal interprété comme un bot — c'est ce que les virtual properties utilisent en interne.

Function Returns
isLikelyBot(ua) true si l'UA correspond à un pattern bot/automation (UA vide compte comme bot)
getTrafficType(ua) AI Agent / Bot / Automation / Regular
getTrafficCategory(ua) sous-catégorie ; regular pour les humains
getBotType(ua) même sous-catégorie mais chaîne vide pour les humains — pratique pour filtrer
getBotName(ua) nom du bot ; vide pour les humains
getBotOperator(ua) opérateur/entreprise ; vide pour les humains

Types de trafic — ce qu'il faut garder vs supprimer

getTrafficType / $virt_traffic_type trie chaque requête en quatre catégories. Le geste par défaut diffère selon la catégorie — ne les traite pas toutes comme du bruit :

Type Ce que c'est Geste par défaut
Regular Visiteurs humains Garder
AI Agent Crawlers IA, moteurs de recherche IA, assistants IA (GPTBot, ClaudeBot, PerplexityBot, ChatGPT-User) Souvent mesurer, ne pas supprimer — c'est ainsi que les outils IA trouvent et citent le contenu
Bot Crawlers de recherche, outils SEO, aperçus sociaux, monitoring (Googlebot, AhrefsBot, Pingdom) Exclure des métriques humaines ; suivre séparément pour le SEO
Automation HTTP clients et headless browsers (curl, python-requests, Puppeteer) Généralement du bruit — exclure

Recettes

Exclure les bots d'un insight (humains uniquement)

Ajoute un filtre de property $virt_is_bot exact false :

{ "key": "$virt_is_bot", "value": ["false"], "operator": "exact", "type": "event" }

Dépose-le dans n'importe quelle properties de TrendsQuery / FunnelsQuery / etc. Le nombre de visiteurs, sessions et pageviews reflète ensuite le trafic humain uniquement, sans modifier les données stockées.

Pour exclure une tranche plus étroite (ex. garder les agents IA mais supprimer monitoring + automation), filtre plutôt sur $virt_traffic_type ou $virt_traffic_category avec operator: is_not.

Quelle part du trafic est automatisée

Divise une tendance de pageview par $virt_traffic_type :

{
  "kind": "TrendsQuery",
  "dateRange": { "date_from": "-30d" },
  "series": [{ "kind": "EventsNode", "event": "$pageview", "math": "total" }],
  "breakdownFilter": { "breakdown": "$virt_traffic_type", "breakdown_type": "event" },
  "trendsFilter": { "display": "ActionsBarValue" }
}

Quels bots / opérateurs nous visitent

Filtre sur les bots et divise par nom (ou $virt_bot_operator pour le niveau entreprise) :

{
  "kind": "TrendsQuery",
  "dateRange": { "date_from": "-30d" },
  "series": [{ "kind": "EventsNode", "event": "$pageview", "math": "total" }],
  "properties": [{ "key": "$virt_is_bot", "value": ["true"], "operator": "exact", "type": "event" }],
  "breakdownFilter": { "breakdown": "$virt_bot_name", "breakdown_type": "event", "breakdown_limit": 25 },
  "trendsFilter": { "display": "ActionsBarValue" }
}

Mesurer le trafic des agents IA spécifiquement

Filtre $virt_traffic_type exact AI Agent, divise par $virt_bot_operator pour voir quels outils (OpenAI, Anthropic, Perplexity, …) lisent ton site et quelles pages ils visitent.

Équivalents en SQL brut

-- pageviews humains uniquement
SELECT count() AS human_pageviews
FROM events
WHERE event = '$pageview'
    AND NOT isLikelyBot(coalesce(nullIf(properties.$raw_user_agent, ''), properties.$user_agent))

-- top bots par hits
SELECT
    getBotName(coalesce(nullIf(properties.$raw_user_agent, ''), properties.$user_agent)) AS bot,
    getBotOperator(coalesce(nullIf(properties.$raw_user_agent, ''), properties.$user_agent)) AS operator,
    count() AS hits
FROM events
WHERE event = '$pageview'
    AND isLikelyBot(coalesce(nullIf(properties.$raw_user_agent, ''), properties.$user_agent))
GROUP BY bot, operator
ORDER BY hits DESC

Voir les bots qui n'exécutent pas JavaScript

La plupart des crawlers et agents IA n'exécutent jamais JS, donc posthog-js ne déclenche jamais un $pageview pour eux — ils sont invisibles pour l'analytics côté client. Pour les mesurer, le projet doit transférer les access logs serveur en tant qu'événements $http_log portant $raw_user_agent. Si un utilisateur demande « pourquoi ne vois-je pas GPTBot alors que je sais qu'il nous crawle ? », la réponse est presque toujours : pas d'ingestion $http_log. Oriente-le vers la capture côté serveur (la source Vercel logs, un edge worker, ou l'API capture) avant de construire des insights sur les bots.

Pièges

  • Nécessite un user agent capturé. La classification est calculée au moment de la requête à partir du $raw_user_agent / $user_agent de l'événement, donc elle fonctionne sur n'importe quel événement historique — pas besoin de restreindre dateRange.date_from. La seule exigence est qu'un user agent ait été capturé ; les événements de sources qui n'en définissent jamais ne peuvent pas être classifiés (et les UAs vides retombent sur Automation / no_user_agent, voir ci-dessous).
  • isLikelyBot est "likely". La détection est une heuristique user-agent — certains bots usurpent les UAs de vrais navigateurs, et certains outils légitimes utilisent des UAs semblables à ceux de bots. Traite-la comme du best-effort, pas comme la vérité absolue.
  • User agent vide = bot. Les requêtes sans UA (serveur-à-serveur, SDKs mal configurés) se classent comme Automation / no_user_agent, donc isLikelyBot retourne true.
  • Ne supprime pas silencieusement le filtre host. Si l'utilisateur est limité à un domaine, hérite $host dans properties — l'omettre change la réponse.
  • Les définitions de bots évoluent. La liste des bots détectés change au fil du temps, donc réexécuter la même requête plus tard peut classer différemment les événements plus anciens.

Skills similaires