@shware/analytics 8.15.0 → 8.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/attribution/classify.cjs +15 -3
  2. package/dist/attribution/classify.cjs.map +1 -1
  3. package/dist/attribution/classify.d.cts +2 -1
  4. package/dist/attribution/classify.d.cts.map +1 -1
  5. package/dist/attribution/classify.d.mts +2 -1
  6. package/dist/attribution/classify.d.mts.map +1 -1
  7. package/dist/attribution/classify.mjs +15 -3
  8. package/dist/attribution/classify.mjs.map +1 -1
  9. package/dist/attribution/vocabulary.cjs +100 -19
  10. package/dist/attribution/vocabulary.cjs.map +1 -1
  11. package/dist/attribution/vocabulary.d.cts +16 -4
  12. package/dist/attribution/vocabulary.d.cts.map +1 -1
  13. package/dist/attribution/vocabulary.d.mts +16 -4
  14. package/dist/attribution/vocabulary.d.mts.map +1 -1
  15. package/dist/attribution/vocabulary.mjs +100 -19
  16. package/dist/attribution/vocabulary.mjs.map +1 -1
  17. package/dist/bot/index.cjs +39 -1
  18. package/dist/bot/index.cjs.map +1 -1
  19. package/dist/bot/index.d.cts +3 -2
  20. package/dist/bot/index.d.cts.map +1 -1
  21. package/dist/bot/index.d.mts +3 -2
  22. package/dist/bot/index.d.mts.map +1 -1
  23. package/dist/bot/index.mjs +39 -1
  24. package/dist/bot/index.mjs.map +1 -1
  25. package/dist/schema/index.cjs +3 -1
  26. package/dist/schema/index.cjs.map +1 -1
  27. package/dist/schema/index.d.cts +18 -6
  28. package/dist/schema/index.d.cts.map +1 -1
  29. package/dist/schema/index.d.mts +18 -6
  30. package/dist/schema/index.d.mts.map +1 -1
  31. package/dist/schema/index.mjs +3 -1
  32. package/dist/schema/index.mjs.map +1 -1
  33. package/dist/server/openai-conversions-api.cjs +1 -0
  34. package/dist/server/openai-conversions-api.cjs.map +1 -1
  35. package/dist/server/openai-conversions-api.d.cts.map +1 -1
  36. package/dist/server/openai-conversions-api.d.mts.map +1 -1
  37. package/dist/server/openai-conversions-api.mjs +1 -0
  38. package/dist/server/openai-conversions-api.mjs.map +1 -1
  39. package/dist/track/types.d.cts +3 -1
  40. package/dist/track/types.d.cts.map +1 -1
  41. package/dist/track/types.d.mts +3 -1
  42. package/dist/track/types.d.mts.map +1 -1
  43. package/dist/web/index.cjs +3 -1
  44. package/dist/web/index.cjs.map +1 -1
  45. package/dist/web/index.d.cts.map +1 -1
  46. package/dist/web/index.d.mts.map +1 -1
  47. package/dist/web/index.mjs +3 -1
  48. package/dist/web/index.mjs.map +1 -1
  49. package/dist/web/page-key.cjs +4 -2
  50. package/dist/web/page-key.cjs.map +1 -1
  51. package/dist/web/page-key.d.cts.map +1 -1
  52. package/dist/web/page-key.d.mts.map +1 -1
  53. package/dist/web/page-key.mjs +4 -2
  54. package/dist/web/page-key.mjs.map +1 -1
  55. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/bot/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAsBa;YAeD,sBAAsB;;;;;YAMtB;EACN;EAAc;EAAkB,cAAc;;EAC9C;EAAe;EAAgB;;qBAExB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4BX,mEAAU,qDAAA,mDAAA,0DAAA,8CAAA,oDAAA,4DAAA,gDAAA,iDAAA,gDAAA,mDAAA,kDAAA,iDAAA,sDAAA,oDAAA,2DAAA,qDAAA,iDAAA,gDAAA,uDAAA,uEAAA,mDAAA,2DAAA,wDAAA,gDAAA,gDAAA,+CAAA,mDAAA,4CAAA,8CAAA,iDAAA,oDAAA,iDAAA,mDAAA,6CAAA,0CAAA,4CAAA,kDAAA,qDAAA,kDAAA,mDAAA,gDAAA,6CAAA,6CAAA,2CAAA,2CAAA,sDAAA,2CAAA,8CAAA,iDAAA,uDAAA,gDAAA,+CAAA,0CAAA,0DAAA,8CAAA,4CAAA,2CAAA,iDAAA,6CAAA,2CAAA,6CAAA,iDAAA,gDAAA,8CAAA,6CAAA,4CAAA,4CAAA,mDAAA,uDAAA,qDAAA,oDAAA,kDAAA,+CAAA,8CAAA,mDAAA,6CAAA,6CAAA,gDAAA,0CAAA,iEAAA,0DAAA,8CAAA,iDAAA,kDAAA,+CAAA,iDAAA,kDAAA,+CAAA,mDAAA,gDAAA,uDAAA,sDAAA,kDAAA,+CAAA,8CAAA,sDAAA,8CAAA,4CAAA,qDAAA,0DAAA,wDAAA,wDAAA,6CAAA,2CAAA,4CAAA,6CAAA,0CAAA,yCAAA,2CAAA,iDAAA,8CAAA,0CAAA,gDAAA,0CAAA,sEAAA,8CAAA,4CAAA,6CAAA,6CAAA,6CAAA,8CAAA,8CAAA,+CAAA,4CAAA,yCAAA,kDAAA,wDAAA,oDAAA,gDAAA,iDAAA,oDAAA,kDAAA,oDAAA,oDAAA,8CAAA,kDAAA,oDAAA,iDAAA,kDAAA,6CAAA,mDAAA,iDAAA,kDAAA,kDAAA,iDAAA,oDAAA,8CAAA,yDAAA,4CAAA,gDAAA,+CAAA,6CAAA,iDAAA,4CAAA,4CAAA,mDAAA,gDAAA,iEAAA,8CAAA,2CAAA,+CAAA,oDAAA,wDAAA,2CAAA,kDAAA,8CAAA,6CAAA,8CAAA,8CAAA,kDAAA,gDAAA,0CAAA,yCAAA,2CAAA,yDAAA,oDAAA,mDAAA,qDAAA,oDAAA,mDAAA,kDAAA,qDAAA,sDAAA,0CAAA,0CAAA,qDAAA,mDAAA,6CAAA,2CAAA,4CAAA,oDAAA,4CAAA,0CAAA,2CAAA,gDAAA,4CAAA,oDAAA,8CAAA,iDAAA,4CAAA,wDAAA,gDAAA;;;;;;;wBA0bP,iBAAiB,mBAAmB;;;;;;;;;;;;;;wBA+BpC,MAAM,MAAM,YAAY"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/bot/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAsBa;YAeD,sBAAsB;;;;;YAMtB;EACN;EAAc;EAAkB,cAAc;;EAC9C;EAAe;EAAgB;;qBAExB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4BX,mEAAU,qDAAA,mDAAA,0DAAA,8CAAA,oDAAA,4DAAA,gDAAA,iDAAA,gDAAA,mDAAA,kDAAA,iDAAA,sDAAA,oDAAA,2DAAA,qDAAA,iDAAA,gDAAA,+CAAA,gDAAA,uDAAA,uEAAA,mDAAA,2DAAA,wDAAA,gDAAA,gDAAA,+CAAA,mDAAA,4CAAA,8CAAA,iDAAA,oDAAA,iDAAA,mDAAA,6CAAA,0CAAA,4CAAA,kDAAA,qDAAA,kDAAA,mDAAA,gDAAA,6CAAA,6CAAA,2CAAA,2CAAA,sDAAA,2CAAA,2CAAA,8CAAA,iDAAA,uDAAA,gDAAA,+CAAA,0CAAA,0DAAA,8CAAA,4CAAA,2CAAA,iDAAA,6CAAA,2CAAA,6CAAA,iDAAA,kDAAA,iDAAA,gDAAA,8CAAA,6CAAA,4CAAA,4CAAA,mDAAA,uDAAA,qDAAA,oDAAA,kDAAA,+CAAA,8CAAA,mDAAA,6CAAA,6CAAA,gDAAA,0CAAA,iEAAA,0DAAA,8CAAA,iDAAA,kDAAA,+CAAA,iDAAA,kDAAA,+CAAA,mDAAA,gDAAA,uDAAA,sDAAA,kDAAA,+CAAA,8CAAA,sDAAA,8CAAA,4CAAA,qDAAA,0DAAA,wDAAA,wDAAA,6CAAA,2CAAA,4CAAA,6CAAA,0CAAA,yCAAA,2CAAA,iDAAA,8CAAA,0CAAA,gDAAA,0CAAA,sEAAA,8CAAA,4CAAA,6CAAA,6CAAA,6CAAA,8CAAA,8CAAA,+CAAA,4CAAA,yCAAA,kDAAA,wDAAA,oDAAA,gDAAA,iDAAA,oDAAA,kDAAA,oDAAA,oDAAA,8CAAA,kDAAA,oDAAA,iDAAA,kDAAA,6CAAA,mDAAA,iDAAA,kDAAA,kDAAA,iDAAA,oDAAA,8CAAA,yDAAA,4CAAA,gDAAA,+CAAA,6CAAA,iDAAA,4CAAA,4CAAA,mDAAA,gDAAA,iEAAA,8CAAA,2CAAA,+CAAA,oDAAA,wDAAA,2CAAA,kDAAA,8CAAA,6CAAA,8CAAA,8CAAA,kDAAA,gDAAA,0CAAA,yCAAA,2CAAA,yDAAA,oDAAA,mDAAA,qDAAA,oDAAA,mDAAA,kDAAA,qDAAA,sDAAA,0CAAA,0CAAA,qDAAA,mDAAA,6CAAA,2CAAA,4CAAA,oDAAA,4CAAA,0CAAA,2CAAA,gDAAA,4CAAA,oDAAA,8CAAA,iDAAA,4CAAA,wDAAA,gDAAA;;;;;;;wBAocP,iBAAiB,mBAAmB;;;;;;;;;;;;;;;wBA4CpC,MAAM,MAAM,YAAY"}
@@ -61,7 +61,7 @@ export declare const NOT_A_BOT: Bot;
61
61
  * come first. The long tail is left to the generic pattern, filed as `other` and named by
62
62
  * `nameOfUnknownBot`; add a bot here when it is worth its own category or name in a dashboard.
63
63
  */
64
- export declare const NAMED_BOTS: readonly [readonly ["Meta-ExternalAds", "advertising", RegExp], readonly ["facebookcatalog", "advertising", RegExp], readonly ["AdsBot-Google", "advertising", RegExp], readonly ["Mediapartners-Google", "advertising", RegExp], readonly ["AdIdxBot", "advertising", RegExp], readonly ["Google-AdWords", "advertising", RegExp], readonly ["Google-Ads-Conversions", "advertising", RegExp], readonly ["OAI-AdsBot", "advertising", RegExp], readonly ["SnapchatAds", "advertising", RegExp], readonly ["Taboolabot", "advertising", RegExp], readonly ["ChatGPT-User", "ai_assistant", RegExp], readonly ["Claude-User", "ai_assistant", RegExp], readonly ["Claude-Web", "ai_assistant", RegExp], readonly ["Perplexity-User", "ai_assistant", RegExp], readonly ["DuckAssistBot", "ai_assistant", RegExp], readonly ["Meta-ExternalFetcher", "ai_assistant", RegExp], readonly ["MistralAI-User", "ai_assistant", RegExp], readonly ["Manus-User", "ai_assistant", RegExp], readonly ["Amzn-User", "ai_assistant", RegExp], readonly ["amazon-QBusiness", "ai_assistant", RegExp], readonly ["Amazon-Bedrock-AgentCore-Browser", "ai_assistant", RegExp], readonly ["Google-Agent", "ai_assistant", RegExp], readonly ["Gemini-Deep-Research", "ai_assistant", RegExp], readonly ["Google-NotebookLM", "ai_assistant", RegExp], readonly ["Kimi-User", "ai_assistant", RegExp], readonly ["TongyiBot", "ai_assistant", RegExp], readonly ["YiyanBot", "ai_assistant", RegExp], readonly ["kagi-fetcher", "ai_assistant", RegExp], readonly ["Devin", "ai_assistant", RegExp], readonly ["NovaAct", "ai_assistant", RegExp], readonly ["OAI-SearchBot", "ai_search", RegExp], readonly ["Claude-SearchBot", "ai_search", RegExp], readonly ["PerplexityBot", "ai_search", RegExp], readonly ["Meta-WebIndexer", "ai_search", RegExp], readonly ["Amazonbot", "ai_search", RegExp], readonly ["YouBot", "ai_search", RegExp], readonly ["PhindBot", "ai_search", RegExp], readonly ["Amzn-SearchBot", "ai_search", RegExp], readonly ["AzureAI-SearchBot", "ai_search", RegExp], readonly ["Kimi-SearchBot", "ai_search", RegExp], readonly ["MistralAI-Index", "ai_search", RegExp], readonly ["ExaSearchBot", "ai_search", RegExp], readonly ["TavilyBot", "ai_search", RegExp], readonly ["LinkupBot", "ai_search", RegExp], readonly ["iAskBot", "ai_search", RegExp], readonly ["Andibot", "ai_search", RegExp], readonly ["Cloudflare-AutoRAG", "ai_search", RegExp], readonly ["GPTBot", "ai_crawler", RegExp], readonly ["ClaudeBot", "ai_crawler", RegExp], readonly ["anthropic-ai", "ai_crawler", RegExp], readonly ["Meta-ExternalAgent", "ai_crawler", RegExp], readonly ["FacebookBot", "ai_crawler", RegExp], readonly ["Bytespider", "ai_crawler", RegExp], readonly ["CCBot", "ai_crawler", RegExp], readonly ["Google-CloudVertexBot", "ai_crawler", RegExp], readonly ["cohere-ai", "ai_crawler", RegExp], readonly ["Diffbot", "ai_crawler", RegExp], readonly ["Omgili", "ai_crawler", RegExp], readonly ["ImagesiftBot", "ai_crawler", RegExp], readonly ["Timpibot", "ai_crawler", RegExp], readonly ["AI2Bot", "ai_crawler", RegExp], readonly ["PanguBot", "ai_crawler", RegExp], readonly ["TikTokSpider", "ai_crawler", RegExp], readonly ["DeepSeekBot", "ai_crawler", RegExp], readonly ["DoubaoBot", "ai_crawler", RegExp], readonly ["ERNIEBot", "ai_crawler", RegExp], readonly ["QwenBot", "ai_crawler", RegExp], readonly ["KimiBot", "ai_crawler", RegExp], readonly ["ChatGLM-Spider", "ai_crawler", RegExp], readonly ["MistralAI-Training", "ai_crawler", RegExp], readonly ["YandexAdditional", "ai_crawler", RegExp], readonly ["Google-Extended", "ai_crawler", RegExp], readonly ["Amazon Kendra", "ai_crawler", RegExp], readonly ["bedrockbot", "ai_crawler", RegExp], readonly ["Brightbot", "ai_crawler", RegExp], readonly ["FirecrawlAgent", "ai_crawler", RegExp], readonly ["Crawl4AI", "ai_crawler", RegExp], readonly ["ApifyBot", "ai_crawler", RegExp], readonly ["img2dataset", "ai_crawler", RegExp], readonly ["LAION", "ai_crawler", RegExp], readonly ["Cloudflare Browser Rendering", "ai_crawler", RegExp], readonly ["facebookexternalhit", "link_preview", RegExp], readonly ["Facebot", "link_preview", RegExp], readonly ["Twitterbot", "link_preview", RegExp], readonly ["LinkedInBot", "link_preview", RegExp], readonly ["Slackbot", "link_preview", RegExp], readonly ["Discordbot", "link_preview", RegExp], readonly ["TelegramBot", "link_preview", RegExp], readonly ["WhatsApp", "link_preview", RegExp], readonly ["Pinterestbot", "link_preview", RegExp], readonly ["redditbot", "link_preview", RegExp], readonly ["Snap URL Preview", "link_preview", RegExp], readonly ["SkypeUriPreview", "link_preview", RegExp], readonly ["BingPreview", "link_preview", RegExp], readonly ["Iframely", "link_preview", RegExp], readonly ["Embedly", "link_preview", RegExp], readonly ["KakaoTalk-scrap", "link_preview", RegExp], readonly ["vkShare", "link_preview", RegExp], readonly ["Viber", "link_preview", RegExp], readonly ["Bluesky Cardyb", "link_preview", RegExp], readonly ["Google-PageRenderer", "link_preview", RegExp], readonly ["vercel-screenshot", "link_preview", RegExp], readonly ["Google-InspectionTool", "seo_tool", RegExp], readonly ["Lighthouse", "seo_tool", RegExp], readonly ["GTmetrix", "seo_tool", RegExp], readonly ["AhrefsBot", "seo_tool", RegExp], readonly ["SemrushBot", "seo_tool", RegExp], readonly ["MJ12bot", "seo_tool", RegExp], readonly ["DotBot", "seo_tool", RegExp], readonly ["rogerbot", "seo_tool", RegExp], readonly ["Screaming Frog", "seo_tool", RegExp], readonly ["SerpstatBot", "seo_tool", RegExp], readonly ["BLEXBot", "seo_tool", RegExp], readonly ["DataForSeoBot", "seo_tool", RegExp], readonly ["HubSpot", "seo_tool", RegExp], readonly ["Google-Structured-Data-Testing-Tool", "seo_tool", RegExp], readonly ["WebPageTest", "seo_tool", RegExp], readonly ["DareBoost", "seo_tool", RegExp], readonly ["Barkrowler", "seo_tool", RegExp], readonly ["SE Ranking", "seo_tool", RegExp], readonly ["BrightEdge", "seo_tool", RegExp], readonly ["SearchAtlas", "seo_tool", RegExp], readonly ["Siteimprove", "seo_tool", RegExp], readonly ["Dataprovider", "seo_tool", RegExp], readonly ["Meltwater", "seo_tool", RegExp], readonly ["Awario", "seo_tool", RegExp], readonly ["Googlebot", "search_crawler", RegExp], readonly ["Storebot-Google", "search_crawler", RegExp], readonly ["GoogleOther", "search_crawler", RegExp], readonly ["Bingbot", "search_crawler", RegExp], readonly ["Applebot", "search_crawler", RegExp], readonly ["Baiduspider", "search_crawler", RegExp], readonly ["YandexBot", "search_crawler", RegExp], readonly ["DuckDuckBot", "search_crawler", RegExp], readonly ["Yahoo Slurp", "search_crawler", RegExp], readonly ["Sogou", "search_crawler", RegExp], readonly ["360Spider", "search_crawler", RegExp], readonly ["YisouSpider", "search_crawler", RegExp], readonly ["PetalBot", "search_crawler", RegExp], readonly ["SeznamBot", "search_crawler", RegExp], readonly ["Yeti", "search_crawler", RegExp], readonly ["Linespider", "search_crawler", RegExp], readonly ["Qwantbot", "search_crawler", RegExp], readonly ["coccocbot", "search_crawler", RegExp], readonly ["MojeekBot", "search_crawler", RegExp], readonly ["Bravebot", "search_crawler", RegExp], readonly ["SeekportBot", "search_crawler", RegExp], readonly ["mwmbl", "search_crawler", RegExp], readonly ["Internet Archive", "search_crawler", RegExp], readonly ["Pingdom", "monitoring", RegExp], readonly ["UptimeRobot", "monitoring", RegExp], readonly ["StatusCake", "monitoring", RegExp], readonly ["Site24x7", "monitoring", RegExp], readonly ["Better Stack", "monitoring", RegExp], readonly ["Datadog", "monitoring", RegExp], readonly ["Checkly", "monitoring", RegExp], readonly ["NewRelicPinger", "monitoring", RegExp], readonly ["Uptime-Kuma", "monitoring", RegExp], readonly ["Grafana Synthetic Monitoring", "monitoring", RegExp], readonly ["Dynatrace", "monitoring", RegExp], readonly ["Splunk", "monitoring", RegExp], readonly ["Catchpoint", "monitoring", RegExp], readonly ["Ghost Inspector", "monitoring", RegExp], readonly ["DigitalOcean Uptime", "monitoring", RegExp], readonly ["OhDear", "monitoring", RegExp], readonly ["Google-Safety", "monitoring", RegExp], readonly ["Cookiebot", "monitoring", RegExp], readonly ["OneTrust", "monitoring", RegExp], readonly ["CookieHub", "monitoring", RegExp], readonly ["Detectify", "monitoring", RegExp], readonly ["CensysInspect", "monitoring", RegExp], readonly ["BitSightBot", "monitoring", RegExp], readonly ["zgrab", "monitoring", RegExp], readonly ["Nmap", "monitoring", RegExp], readonly ["Stripe", "monitoring", RegExp], readonly ["HeadlessChrome", "headless_browser", RegExp], readonly ["PhantomJS", "headless_browser", RegExp], readonly ["SlimerJS", "headless_browser", RegExp], readonly ["Playwright", "headless_browser", RegExp], readonly ["Puppeteer", "headless_browser", RegExp], readonly ["Selenium", "headless_browser", RegExp], readonly ["Cypress", "headless_browser", RegExp], readonly ["Lightpanda", "headless_browser", RegExp], readonly ["wkhtmltopdf", "headless_browser", RegExp], readonly ["curl", "http_client", RegExp], readonly ["Wget", "http_client", RegExp], readonly ["python-requests", "http_client", RegExp], readonly ["python-urllib", "http_client", RegExp], readonly ["aiohttp", "http_client", RegExp], readonly ["httpx", "http_client", RegExp], readonly ["Scrapy", "http_client", RegExp], readonly ["Go-http-client", "http_client", RegExp], readonly ["okhttp", "http_client", RegExp], readonly ["Java", "http_client", RegExp], readonly ["axios", "http_client", RegExp], readonly ["node-fetch", "http_client", RegExp], readonly ["undici", "http_client", RegExp], readonly ["PostmanRuntime", "http_client", RegExp], readonly ["insomnia", "http_client", RegExp], readonly ["libwww-perl", "http_client", RegExp], readonly ["Guzzle", "http_client", RegExp], readonly ["Google-Apps-Script", "http_client", RegExp], readonly ["GoogleDocs", "http_client", RegExp]];
64
+ export declare const NAMED_BOTS: readonly [readonly ["Meta-ExternalAds", "advertising", RegExp], readonly ["facebookcatalog", "advertising", RegExp], readonly ["AdsBot-Google", "advertising", RegExp], readonly ["Mediapartners-Google", "advertising", RegExp], readonly ["AdIdxBot", "advertising", RegExp], readonly ["Google-AdWords", "advertising", RegExp], readonly ["Google-Ads-Conversions", "advertising", RegExp], readonly ["OAI-AdsBot", "advertising", RegExp], readonly ["SnapchatAds", "advertising", RegExp], readonly ["Taboolabot", "advertising", RegExp], readonly ["ChatGPT-User", "ai_assistant", RegExp], readonly ["Claude-User", "ai_assistant", RegExp], readonly ["Claude-Web", "ai_assistant", RegExp], readonly ["Perplexity-User", "ai_assistant", RegExp], readonly ["DuckAssistBot", "ai_assistant", RegExp], readonly ["Meta-ExternalFetcher", "ai_assistant", RegExp], readonly ["MistralAI-User", "ai_assistant", RegExp], readonly ["Manus-User", "ai_assistant", RegExp], readonly ["Shap-User", "ai_assistant", RegExp], readonly ["QuillBot", "ai_assistant", RegExp], readonly ["Amzn-User", "ai_assistant", RegExp], readonly ["amazon-QBusiness", "ai_assistant", RegExp], readonly ["Amazon-Bedrock-AgentCore-Browser", "ai_assistant", RegExp], readonly ["Google-Agent", "ai_assistant", RegExp], readonly ["Gemini-Deep-Research", "ai_assistant", RegExp], readonly ["Google-NotebookLM", "ai_assistant", RegExp], readonly ["Kimi-User", "ai_assistant", RegExp], readonly ["TongyiBot", "ai_assistant", RegExp], readonly ["YiyanBot", "ai_assistant", RegExp], readonly ["kagi-fetcher", "ai_assistant", RegExp], readonly ["Devin", "ai_assistant", RegExp], readonly ["NovaAct", "ai_assistant", RegExp], readonly ["OAI-SearchBot", "ai_search", RegExp], readonly ["Claude-SearchBot", "ai_search", RegExp], readonly ["PerplexityBot", "ai_search", RegExp], readonly ["Meta-WebIndexer", "ai_search", RegExp], readonly ["Amazonbot", "ai_search", RegExp], readonly ["YouBot", "ai_search", RegExp], readonly ["PhindBot", "ai_search", RegExp], readonly ["Amzn-SearchBot", "ai_search", RegExp], readonly ["AzureAI-SearchBot", "ai_search", RegExp], readonly ["Kimi-SearchBot", "ai_search", RegExp], readonly ["MistralAI-Index", "ai_search", RegExp], readonly ["ExaSearchBot", "ai_search", RegExp], readonly ["TavilyBot", "ai_search", RegExp], readonly ["LinkupBot", "ai_search", RegExp], readonly ["iAskBot", "ai_search", RegExp], readonly ["Andibot", "ai_search", RegExp], readonly ["Cloudflare-AutoRAG", "ai_search", RegExp], readonly ["ShapBot", "ai_search", RegExp], readonly ["GPTBot", "ai_crawler", RegExp], readonly ["ClaudeBot", "ai_crawler", RegExp], readonly ["anthropic-ai", "ai_crawler", RegExp], readonly ["Meta-ExternalAgent", "ai_crawler", RegExp], readonly ["FacebookBot", "ai_crawler", RegExp], readonly ["Bytespider", "ai_crawler", RegExp], readonly ["CCBot", "ai_crawler", RegExp], readonly ["Google-CloudVertexBot", "ai_crawler", RegExp], readonly ["cohere-ai", "ai_crawler", RegExp], readonly ["Diffbot", "ai_crawler", RegExp], readonly ["Omgili", "ai_crawler", RegExp], readonly ["ImagesiftBot", "ai_crawler", RegExp], readonly ["Timpibot", "ai_crawler", RegExp], readonly ["AI2Bot", "ai_crawler", RegExp], readonly ["PanguBot", "ai_crawler", RegExp], readonly ["PromptingBot", "ai_crawler", RegExp], readonly ["Reflectionbot", "ai_crawler", RegExp], readonly ["TikTokSpider", "ai_crawler", RegExp], readonly ["DeepSeekBot", "ai_crawler", RegExp], readonly ["DoubaoBot", "ai_crawler", RegExp], readonly ["ERNIEBot", "ai_crawler", RegExp], readonly ["QwenBot", "ai_crawler", RegExp], readonly ["KimiBot", "ai_crawler", RegExp], readonly ["ChatGLM-Spider", "ai_crawler", RegExp], readonly ["MistralAI-Training", "ai_crawler", RegExp], readonly ["YandexAdditional", "ai_crawler", RegExp], readonly ["Google-Extended", "ai_crawler", RegExp], readonly ["Amazon Kendra", "ai_crawler", RegExp], readonly ["bedrockbot", "ai_crawler", RegExp], readonly ["Brightbot", "ai_crawler", RegExp], readonly ["FirecrawlAgent", "ai_crawler", RegExp], readonly ["Crawl4AI", "ai_crawler", RegExp], readonly ["ApifyBot", "ai_crawler", RegExp], readonly ["img2dataset", "ai_crawler", RegExp], readonly ["LAION", "ai_crawler", RegExp], readonly ["Cloudflare Browser Rendering", "ai_crawler", RegExp], readonly ["facebookexternalhit", "link_preview", RegExp], readonly ["Facebot", "link_preview", RegExp], readonly ["Twitterbot", "link_preview", RegExp], readonly ["LinkedInBot", "link_preview", RegExp], readonly ["Slackbot", "link_preview", RegExp], readonly ["Discordbot", "link_preview", RegExp], readonly ["TelegramBot", "link_preview", RegExp], readonly ["WhatsApp", "link_preview", RegExp], readonly ["Pinterestbot", "link_preview", RegExp], readonly ["redditbot", "link_preview", RegExp], readonly ["Snap URL Preview", "link_preview", RegExp], readonly ["SkypeUriPreview", "link_preview", RegExp], readonly ["BingPreview", "link_preview", RegExp], readonly ["Iframely", "link_preview", RegExp], readonly ["Embedly", "link_preview", RegExp], readonly ["KakaoTalk-scrap", "link_preview", RegExp], readonly ["vkShare", "link_preview", RegExp], readonly ["Viber", "link_preview", RegExp], readonly ["Bluesky Cardyb", "link_preview", RegExp], readonly ["Google-PageRenderer", "link_preview", RegExp], readonly ["vercel-screenshot", "link_preview", RegExp], readonly ["Google-InspectionTool", "seo_tool", RegExp], readonly ["Lighthouse", "seo_tool", RegExp], readonly ["GTmetrix", "seo_tool", RegExp], readonly ["AhrefsBot", "seo_tool", RegExp], readonly ["SemrushBot", "seo_tool", RegExp], readonly ["MJ12bot", "seo_tool", RegExp], readonly ["DotBot", "seo_tool", RegExp], readonly ["rogerbot", "seo_tool", RegExp], readonly ["Screaming Frog", "seo_tool", RegExp], readonly ["SerpstatBot", "seo_tool", RegExp], readonly ["BLEXBot", "seo_tool", RegExp], readonly ["DataForSeoBot", "seo_tool", RegExp], readonly ["HubSpot", "seo_tool", RegExp], readonly ["Google-Structured-Data-Testing-Tool", "seo_tool", RegExp], readonly ["WebPageTest", "seo_tool", RegExp], readonly ["DareBoost", "seo_tool", RegExp], readonly ["Barkrowler", "seo_tool", RegExp], readonly ["SE Ranking", "seo_tool", RegExp], readonly ["BrightEdge", "seo_tool", RegExp], readonly ["SearchAtlas", "seo_tool", RegExp], readonly ["Siteimprove", "seo_tool", RegExp], readonly ["Dataprovider", "seo_tool", RegExp], readonly ["Meltwater", "seo_tool", RegExp], readonly ["Awario", "seo_tool", RegExp], readonly ["Googlebot", "search_crawler", RegExp], readonly ["Storebot-Google", "search_crawler", RegExp], readonly ["GoogleOther", "search_crawler", RegExp], readonly ["Bingbot", "search_crawler", RegExp], readonly ["Applebot", "search_crawler", RegExp], readonly ["Baiduspider", "search_crawler", RegExp], readonly ["YandexBot", "search_crawler", RegExp], readonly ["DuckDuckBot", "search_crawler", RegExp], readonly ["Yahoo Slurp", "search_crawler", RegExp], readonly ["Sogou", "search_crawler", RegExp], readonly ["360Spider", "search_crawler", RegExp], readonly ["YisouSpider", "search_crawler", RegExp], readonly ["PetalBot", "search_crawler", RegExp], readonly ["SeznamBot", "search_crawler", RegExp], readonly ["Yeti", "search_crawler", RegExp], readonly ["Linespider", "search_crawler", RegExp], readonly ["Qwantbot", "search_crawler", RegExp], readonly ["coccocbot", "search_crawler", RegExp], readonly ["MojeekBot", "search_crawler", RegExp], readonly ["Bravebot", "search_crawler", RegExp], readonly ["SeekportBot", "search_crawler", RegExp], readonly ["mwmbl", "search_crawler", RegExp], readonly ["Internet Archive", "search_crawler", RegExp], readonly ["Pingdom", "monitoring", RegExp], readonly ["UptimeRobot", "monitoring", RegExp], readonly ["StatusCake", "monitoring", RegExp], readonly ["Site24x7", "monitoring", RegExp], readonly ["Better Stack", "monitoring", RegExp], readonly ["Datadog", "monitoring", RegExp], readonly ["Checkly", "monitoring", RegExp], readonly ["NewRelicPinger", "monitoring", RegExp], readonly ["Uptime-Kuma", "monitoring", RegExp], readonly ["Grafana Synthetic Monitoring", "monitoring", RegExp], readonly ["Dynatrace", "monitoring", RegExp], readonly ["Splunk", "monitoring", RegExp], readonly ["Catchpoint", "monitoring", RegExp], readonly ["Ghost Inspector", "monitoring", RegExp], readonly ["DigitalOcean Uptime", "monitoring", RegExp], readonly ["OhDear", "monitoring", RegExp], readonly ["Google-Safety", "monitoring", RegExp], readonly ["Cookiebot", "monitoring", RegExp], readonly ["OneTrust", "monitoring", RegExp], readonly ["CookieHub", "monitoring", RegExp], readonly ["Detectify", "monitoring", RegExp], readonly ["CensysInspect", "monitoring", RegExp], readonly ["BitSightBot", "monitoring", RegExp], readonly ["zgrab", "monitoring", RegExp], readonly ["Nmap", "monitoring", RegExp], readonly ["Stripe", "monitoring", RegExp], readonly ["HeadlessChrome", "headless_browser", RegExp], readonly ["PhantomJS", "headless_browser", RegExp], readonly ["SlimerJS", "headless_browser", RegExp], readonly ["Playwright", "headless_browser", RegExp], readonly ["Puppeteer", "headless_browser", RegExp], readonly ["Selenium", "headless_browser", RegExp], readonly ["Cypress", "headless_browser", RegExp], readonly ["Lightpanda", "headless_browser", RegExp], readonly ["wkhtmltopdf", "headless_browser", RegExp], readonly ["curl", "http_client", RegExp], readonly ["Wget", "http_client", RegExp], readonly ["python-requests", "http_client", RegExp], readonly ["python-urllib", "http_client", RegExp], readonly ["aiohttp", "http_client", RegExp], readonly ["httpx", "http_client", RegExp], readonly ["Scrapy", "http_client", RegExp], readonly ["Go-http-client", "http_client", RegExp], readonly ["okhttp", "http_client", RegExp], readonly ["Java", "http_client", RegExp], readonly ["axios", "http_client", RegExp], readonly ["node-fetch", "http_client", RegExp], readonly ["undici", "http_client", RegExp], readonly ["PostmanRuntime", "http_client", RegExp], readonly ["insomnia", "http_client", RegExp], readonly ["libwww-perl", "http_client", RegExp], readonly ["Guzzle", "http_client", RegExp], readonly ["Google-Apps-Script", "http_client", RegExp], readonly ["GoogleDocs", "http_client", RegExp]];
65
65
  /**
66
66
  * A name for a bot that is not in the named table, from the first of: a token that sounds like
67
67
  * one (`Bytespider`, `ABEvalBot`), the name after `compatible;` (`Google-Read-Aloud`), a product
@@ -80,7 +80,8 @@ export declare function nameOfUnknownBot(userAgent: string, matched: string): st
80
80
  *
81
81
  * In order: a bot we can name; a browser driven by WebDriver (`tags.webdriver`, which the SDK
82
82
  * sets from `navigator.webdriver`, the one sign a scripted browser with a normal user agent
83
- * gives); anything the generic pattern calls automated; no user agent at all.
83
+ * gives); a person in a Meta app (`META_APP`); anything the generic pattern calls automated; no
84
+ * user agent at all.
84
85
  */
85
86
  export declare function botOf(tags: TrackTags): Bot;
86
87
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/bot/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAsBa;YAeD,sBAAsB;;;;;YAMtB;EACN;EAAc;EAAkB,cAAc;;EAC9C;EAAe;EAAgB;;qBAExB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4BX,mEAAU,qDAAA,mDAAA,0DAAA,8CAAA,oDAAA,4DAAA,gDAAA,iDAAA,gDAAA,mDAAA,kDAAA,iDAAA,sDAAA,oDAAA,2DAAA,qDAAA,iDAAA,gDAAA,uDAAA,uEAAA,mDAAA,2DAAA,wDAAA,gDAAA,gDAAA,+CAAA,mDAAA,4CAAA,8CAAA,iDAAA,oDAAA,iDAAA,mDAAA,6CAAA,0CAAA,4CAAA,kDAAA,qDAAA,kDAAA,mDAAA,gDAAA,6CAAA,6CAAA,2CAAA,2CAAA,sDAAA,2CAAA,8CAAA,iDAAA,uDAAA,gDAAA,+CAAA,0CAAA,0DAAA,8CAAA,4CAAA,2CAAA,iDAAA,6CAAA,2CAAA,6CAAA,iDAAA,gDAAA,8CAAA,6CAAA,4CAAA,4CAAA,mDAAA,uDAAA,qDAAA,oDAAA,kDAAA,+CAAA,8CAAA,mDAAA,6CAAA,6CAAA,gDAAA,0CAAA,iEAAA,0DAAA,8CAAA,iDAAA,kDAAA,+CAAA,iDAAA,kDAAA,+CAAA,mDAAA,gDAAA,uDAAA,sDAAA,kDAAA,+CAAA,8CAAA,sDAAA,8CAAA,4CAAA,qDAAA,0DAAA,wDAAA,wDAAA,6CAAA,2CAAA,4CAAA,6CAAA,0CAAA,yCAAA,2CAAA,iDAAA,8CAAA,0CAAA,gDAAA,0CAAA,sEAAA,8CAAA,4CAAA,6CAAA,6CAAA,6CAAA,8CAAA,8CAAA,+CAAA,4CAAA,yCAAA,kDAAA,wDAAA,oDAAA,gDAAA,iDAAA,oDAAA,kDAAA,oDAAA,oDAAA,8CAAA,kDAAA,oDAAA,iDAAA,kDAAA,6CAAA,mDAAA,iDAAA,kDAAA,kDAAA,iDAAA,oDAAA,8CAAA,yDAAA,4CAAA,gDAAA,+CAAA,6CAAA,iDAAA,4CAAA,4CAAA,mDAAA,gDAAA,iEAAA,8CAAA,2CAAA,+CAAA,oDAAA,wDAAA,2CAAA,kDAAA,8CAAA,6CAAA,8CAAA,8CAAA,kDAAA,gDAAA,0CAAA,yCAAA,2CAAA,yDAAA,oDAAA,mDAAA,qDAAA,oDAAA,mDAAA,kDAAA,qDAAA,sDAAA,0CAAA,0CAAA,qDAAA,mDAAA,6CAAA,2CAAA,4CAAA,oDAAA,4CAAA,0CAAA,2CAAA,gDAAA,4CAAA,oDAAA,8CAAA,iDAAA,4CAAA,wDAAA,gDAAA;;;;;;;wBA0bP,iBAAiB,mBAAmB;;;;;;;;;;;;;;wBA+BpC,MAAM,MAAM,YAAY"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/bot/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;qBAsBa;YAeD,sBAAsB;;;;;YAMtB;EACN;EAAc;EAAkB,cAAc;;EAC9C;EAAe;EAAgB;;qBAExB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4BX,mEAAU,qDAAA,mDAAA,0DAAA,8CAAA,oDAAA,4DAAA,gDAAA,iDAAA,gDAAA,mDAAA,kDAAA,iDAAA,sDAAA,oDAAA,2DAAA,qDAAA,iDAAA,gDAAA,+CAAA,gDAAA,uDAAA,uEAAA,mDAAA,2DAAA,wDAAA,gDAAA,gDAAA,+CAAA,mDAAA,4CAAA,8CAAA,iDAAA,oDAAA,iDAAA,mDAAA,6CAAA,0CAAA,4CAAA,kDAAA,qDAAA,kDAAA,mDAAA,gDAAA,6CAAA,6CAAA,2CAAA,2CAAA,sDAAA,2CAAA,2CAAA,8CAAA,iDAAA,uDAAA,gDAAA,+CAAA,0CAAA,0DAAA,8CAAA,4CAAA,2CAAA,iDAAA,6CAAA,2CAAA,6CAAA,iDAAA,kDAAA,iDAAA,gDAAA,8CAAA,6CAAA,4CAAA,4CAAA,mDAAA,uDAAA,qDAAA,oDAAA,kDAAA,+CAAA,8CAAA,mDAAA,6CAAA,6CAAA,gDAAA,0CAAA,iEAAA,0DAAA,8CAAA,iDAAA,kDAAA,+CAAA,iDAAA,kDAAA,+CAAA,mDAAA,gDAAA,uDAAA,sDAAA,kDAAA,+CAAA,8CAAA,sDAAA,8CAAA,4CAAA,qDAAA,0DAAA,wDAAA,wDAAA,6CAAA,2CAAA,4CAAA,6CAAA,0CAAA,yCAAA,2CAAA,iDAAA,8CAAA,0CAAA,gDAAA,0CAAA,sEAAA,8CAAA,4CAAA,6CAAA,6CAAA,6CAAA,8CAAA,8CAAA,+CAAA,4CAAA,yCAAA,kDAAA,wDAAA,oDAAA,gDAAA,iDAAA,oDAAA,kDAAA,oDAAA,oDAAA,8CAAA,kDAAA,oDAAA,iDAAA,kDAAA,6CAAA,mDAAA,iDAAA,kDAAA,kDAAA,iDAAA,oDAAA,8CAAA,yDAAA,4CAAA,gDAAA,+CAAA,6CAAA,iDAAA,4CAAA,4CAAA,mDAAA,gDAAA,iEAAA,8CAAA,2CAAA,+CAAA,oDAAA,wDAAA,2CAAA,kDAAA,8CAAA,6CAAA,8CAAA,8CAAA,kDAAA,gDAAA,0CAAA,yCAAA,2CAAA,yDAAA,oDAAA,mDAAA,qDAAA,oDAAA,mDAAA,kDAAA,qDAAA,sDAAA,0CAAA,0CAAA,qDAAA,mDAAA,6CAAA,2CAAA,4CAAA,oDAAA,4CAAA,0CAAA,2CAAA,gDAAA,4CAAA,oDAAA,8CAAA,iDAAA,4CAAA,wDAAA,gDAAA;;;;;;;wBAocP,iBAAiB,mBAAmB;;;;;;;;;;;;;;;wBA4CpC,MAAM,MAAM,YAAY"}
@@ -155,6 +155,16 @@ const NAMED_BOTS = [
155
155
  "ai_assistant",
156
156
  /manus-user/i
157
157
  ],
158
+ [
159
+ "Shap-User",
160
+ "ai_assistant",
161
+ /shap-user/i
162
+ ],
163
+ [
164
+ "QuillBot",
165
+ "ai_assistant",
166
+ /quillbot/i
167
+ ],
158
168
  [
159
169
  "Amzn-User",
160
170
  "ai_assistant",
@@ -300,6 +310,11 @@ const NAMED_BOTS = [
300
310
  "ai_search",
301
311
  /cloudflare-autorag/i
302
312
  ],
313
+ [
314
+ "ShapBot",
315
+ "ai_search",
316
+ /shapbot/i
317
+ ],
303
318
  [
304
319
  "GPTBot",
305
320
  "ai_crawler",
@@ -375,6 +390,16 @@ const NAMED_BOTS = [
375
390
  "ai_crawler",
376
391
  /pangubot/i
377
392
  ],
393
+ [
394
+ "PromptingBot",
395
+ "ai_crawler",
396
+ /promptingbot/i
397
+ ],
398
+ [
399
+ "Reflectionbot",
400
+ "ai_crawler",
401
+ /reflectionbot/i
402
+ ],
378
403
  [
379
404
  "TikTokSpider",
380
405
  "ai_crawler",
@@ -1102,6 +1127,17 @@ function nameOfUnknownBot(userAgent, matched) {
1102
1127
  return matched.replace(/^\W+|\W+$/g, "").slice(0, 64) || "unknown";
1103
1128
  }
1104
1129
  /**
1130
+ * The request user agent of a page opened in Facebook's or Instagram's in-app browser when the
1131
+ * app sends the page's requests through its own network stack: `[FBAN/FB4A;FBAV/…]`,
1132
+ * `Instagram 445.0.0.34.44 (iPhone18,1; iOS 26_6_1; …) AppleWebKit/420+`. The page itself still
1133
+ * reads a browser's `navigator.userAgent`, which is why PostHog, GA4 and Matomo see a person.
1134
+ * isbot's generic pattern takes both for bots (a long token with no space, a product token that is
1135
+ * no browser's), so they are people here before it runs. Meta's ad prefetch loads only the HTML,
1136
+ * which runs no script and creates no visitor. The in-app browser's own user agent starts with
1137
+ * `Mozilla/5.0`, so the anchors leave it alone.
1138
+ */
1139
+ const META_APP = /^\[FBAN\/|^Instagram \d+(?:\.\d+)+ \(/;
1140
+ /**
1105
1141
  * Whether a web visitor is a bot, which one, and what kind. Run on the server when the visitor
1106
1142
  * is created, with the tags it was created with: the user agent is the request's header
1107
1143
  * (`tags.user_agent`, which the server writes), not anything the client says about itself, so
@@ -1112,7 +1148,8 @@ function nameOfUnknownBot(userAgent, matched) {
1112
1148
  *
1113
1149
  * In order: a bot we can name; a browser driven by WebDriver (`tags.webdriver`, which the SDK
1114
1150
  * sets from `navigator.webdriver`, the one sign a scripted browser with a normal user agent
1115
- * gives); anything the generic pattern calls automated; no user agent at all.
1151
+ * gives); a person in a Meta app (`META_APP`); anything the generic pattern calls automated; no
1152
+ * user agent at all.
1116
1153
  */
1117
1154
  function botOf(tags) {
1118
1155
  const userAgent = typeof tags.user_agent === "string" ? tags.user_agent.trim() : "";
@@ -1128,6 +1165,7 @@ function botOf(tags) {
1128
1165
  bot_name: unknownName ?? "WebDriver",
1129
1166
  bot_category: "headless_browser"
1130
1167
  };
1168
+ if (META_APP.test(userAgent)) return NOT_A_BOT;
1131
1169
  if (unknownName) return {
1132
1170
  is_bot: true,
1133
1171
  bot_name: unknownName,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/bot/index.ts"],"sourcesContent":["import type { TrackTags } from '../track/types';\nimport { GENERIC_BOT } from './generic';\n\n/**\n * What kind of automated visitor a bot is, as the analytics tools that report bots separately\n * group them (PostHog's traffic categories, Cloudflare's verified bot categories, Matomo's\n * DeviceDetector). Stored next to the name so dashboards can group without re-deriving:\n *\n * - search_crawler: indexes pages for a search engine (Googlebot, Bingbot, Baiduspider)\n * - ai_crawler: collects content to train models (GPTBot, ClaudeBot, Meta-ExternalAgent)\n * - ai_search: indexes pages for an AI search product (OAI-SearchBot, PerplexityBot)\n * - ai_assistant: fetches a page because a person asked an assistant to (ChatGPT-User)\n * - advertising: works for an ad system — reviews landing pages, targets or verifies ads\n * (Meta-ExternalAds, AdsBot-Google, Mediapartners-Google)\n * - link_preview: renders the card of a link shared in a feed or a chat (facebookexternalhit)\n * - seo_tool: SEO, marketing and page-speed tools (AhrefsBot, Lighthouse, HubSpot)\n * - monitoring: uptime checks, synthetics and service callers (Pingdom, Stripe)\n * - headless_browser: a scripted browser (HeadlessChrome, Playwright, a WebDriver session)\n * - http_client: a library or command-line client (curl, python-requests)\n * - no_user_agent: a request without a user agent, which no browser sends\n * - other: automated by every sign, but none of the above\n */\nexport const BOT_CATEGORIES = [\n 'search_crawler',\n 'ai_crawler',\n 'ai_search',\n 'ai_assistant',\n 'advertising',\n 'link_preview',\n 'seo_tool',\n 'monitoring',\n 'headless_browser',\n 'http_client',\n 'no_user_agent',\n 'other',\n] as const;\n\nexport type BotCategory = (typeof BOT_CATEGORIES)[number];\n\n/**\n * The verdict, shaped like the columns a product stores it in (`is_bot`, `bot_name`,\n * `bot_category`). A person is `{ is_bot: false, bot_name: null, bot_category: null }`.\n */\nexport type Bot =\n | { is_bot: true; bot_name: string; bot_category: BotCategory }\n | { is_bot: false; bot_name: null; bot_category: null };\n\nexport const NOT_A_BOT: Bot = { is_bot: false, bot_name: null, bot_category: null };\n\n/**\n * Bots we can name, as `[name, category, pattern]`, tried in order; the first match wins.\n *\n * Where the list comes from (checked 2026-09-30):\n * - bowser's bot parsers (the ~25 named bots its `platform.type === 'bot'` reports), which this\n * replaces.\n * - PostHog's `bot_definitions.py` (web analytics traffic classification), for the bots and\n * categories an analytics product sees most.\n * - ai.robots.txt (`robots.json`), for AI crawlers, search bots, assistants and agents.\n * - The operators' own docs for the big ones: Google's crawler list, OpenAI's and Anthropic's\n * bot pages, Meta's web crawlers, Perplexity, Bing, Apple.\n * - Bots seen in production (Meta-ExternalAds, HubSpot, Bytespider).\n * Every entry was run against the real user agents in crawler-user-agents and PostHog's\n * fixtures, and bowser's browser fixtures were run to check no browser is taken for a bot\n * (Sogou's browser against its spider, Pinterest's in-app browser against its bot); see\n * `index.test.ts` for where to get them.\n *\n * The link above each entry is the operator's page about the bot, else its product page, else\n * its Known Agents profile (knownagents.com, formerly Dark Visitors) when the operator has none.\n *\n * Names are the operators' spelling of their user agent token. Order matters where one token\n * contains another or borrows a name: advertising and SEO tools come before the search engines\n * whose names they carry, and the more specific of Meta's, Anthropic's and Perplexity's tokens\n * come first. The long tail is left to the generic pattern, filed as `other` and named by\n * `nameOfUnknownBot`; add a bot here when it is worth its own category or name in a dashboard.\n */\nexport const NAMED_BOTS = [\n // advertising: before the search crawlers, AdsBot and Mediapartners carry Google's name\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalAds', 'advertising', /meta-externalads/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['facebookcatalog', 'advertising', /facebookcatalog/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['AdsBot-Google', 'advertising', /adsbot-google/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['Mediapartners-Google', 'advertising', /mediapartners-google/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['AdIdxBot', 'advertising', /adidxbot/i],\n // https://support.google.com/adwords/answer/2404197\n ['Google-AdWords', 'advertising', /google-adwords/i],\n // https://support.google.com/google-ads/answer/6095821\n ['Google-Ads-Conversions', 'advertising', /google-ads-conversions/i],\n // https://developers.openai.com/api/docs/bots\n ['OAI-AdsBot', 'advertising', /oai-adsbot/i],\n // https://businesshelp.snapchat.com/s/article/adsbot-crawler\n ['SnapchatAds', 'advertising', /snapchatads/i],\n // https://www.taboola.com\n ['Taboolabot', 'advertising', /taboolabot/i],\n\n // AI assistants and agents: a person asked for this page\n // https://developers.openai.com/api/docs/bots\n ['ChatGPT-User', 'ai_assistant', /chatgpt-user/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-User', 'ai_assistant', /claude-user/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-Web', 'ai_assistant', /claude-web/i],\n // https://docs.perplexity.ai/guides/bots\n ['Perplexity-User', 'ai_assistant', /perplexity-user/i],\n // https://duckduckgo.com/duckduckgo-help-pages/results/duckassistbot\n ['DuckAssistBot', 'ai_assistant', /duckassistbot/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalFetcher', 'ai_assistant', /meta-externalfetcher/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-User', 'ai_assistant', /mistralai-user/i],\n // https://knownagents.com/agents/manus-user\n ['Manus-User', 'ai_assistant', /manus-user/i],\n // https://developer.amazon.com/amazonbot\n ['Amzn-User', 'ai_assistant', /amzn-user/i],\n // https://knownagents.com/agents/amazon-qbusiness\n ['amazon-QBusiness', 'ai_assistant', /amazon-qbusiness/i],\n // https://docs.aws.amazon.com/bedrock-agentcore/\n ['Amazon-Bedrock-AgentCore-Browser', 'ai_assistant', /amazon-bedrock-agentcore/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-Agent', 'ai_assistant', /google-?agent/i],\n // https://gemini.google/overview/deep-research/\n ['Gemini-Deep-Research', 'ai_assistant', /gemini-deep-research/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-NotebookLM', 'ai_assistant', /google-notebooklm/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['Kimi-User', 'ai_assistant', /kimi-(?:user|agent)/i],\n // https://knownagents.com/agents/tongyibot\n ['TongyiBot', 'ai_assistant', /tongyibot/i],\n // https://knownagents.com/agents/yiyanbot\n ['YiyanBot', 'ai_assistant', /yiyanbot/i],\n // https://help.kagi.com/kagi/ai/kagi-ai.html\n ['kagi-fetcher', 'ai_assistant', /kagi-fetcher/i],\n // https://devin.ai\n ['Devin', 'ai_assistant', /\\bdevin\\/\\d/i],\n // https://knownagents.com/agents/novaact\n ['NovaAct', 'ai_assistant', /novaact/i],\n\n // AI search\n // https://developers.openai.com/api/docs/bots\n ['OAI-SearchBot', 'ai_search', /oai-searchbot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-SearchBot', 'ai_search', /claude-searchbot/i],\n // https://docs.perplexity.ai/guides/bots\n ['PerplexityBot', 'ai_search', /perplexitybot/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-WebIndexer', 'ai_search', /meta-webindexer/i],\n // https://developer.amazon.com/amazonbot\n ['Amazonbot', 'ai_search', /amazonbot/i],\n // https://knownagents.com/agents/youbot\n ['YouBot', 'ai_search', /youbot/i],\n // https://knownagents.com/agents/phindbot\n ['PhindBot', 'ai_search', /phindbot/i],\n // https://developer.amazon.com/amazonbot\n ['Amzn-SearchBot', 'ai_search', /amzn-searchbot/i],\n // https://knownagents.com/agents/azureai-searchbot\n ['AzureAI-SearchBot', 'ai_search', /azureai-searchbot/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['Kimi-SearchBot', 'ai_search', /kimi-searchbot/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-Index', 'ai_search', /mistralai-index/i],\n // https://knownagents.com/agents/exasearchbot\n ['ExaSearchBot', 'ai_search', /exasearchbot|\\bexabot/i],\n // https://knownagents.com/agents/tavilybot\n ['TavilyBot', 'ai_search', /tavilybot/i],\n // https://linkup.so/bot\n ['LinkupBot', 'ai_search', /linkupbot/i],\n // https://knownagents.com/agents/iaskspider\n ['iAskBot', 'ai_search', /iask(?:bot|spider)/i],\n ['Andibot', 'ai_search', /andibot/i],\n // https://developers.cloudflare.com/autorag\n ['Cloudflare-AutoRAG', 'ai_search', /cloudflare-autorag/i],\n\n // AI training\n // https://developers.openai.com/api/docs/bots\n ['GPTBot', 'ai_crawler', /gptbot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['ClaudeBot', 'ai_crawler', /claudebot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['anthropic-ai', 'ai_crawler', /anthropic-ai/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalAgent', 'ai_crawler', /meta-externalagent/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['FacebookBot', 'ai_crawler', /facebookbot/i],\n // https://knownagents.com/agents/bytespider\n ['Bytespider', 'ai_crawler', /bytespider/i],\n // https://commoncrawl.org/ccbot\n ['CCBot', 'ai_crawler', /ccbot/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-CloudVertexBot', 'ai_crawler', /google-cloudvertexbot/i],\n // https://knownagents.com/agents/cohere-training-data-crawler\n ['cohere-ai', 'ai_crawler', /cohere-(?:ai|training-data-crawler)/i],\n // https://www.diffbot.com/docs/crawl/faq/robots-txt\n ['Diffbot', 'ai_crawler', /diffbot/i],\n // https://knownagents.com/agents/webzio-extended\n ['Omgili', 'ai_crawler', /omgili|webzio-extended/i],\n // https://imagesift.com/about\n ['ImagesiftBot', 'ai_crawler', /imagesiftbot/i],\n // https://www.timpi.io\n ['Timpibot', 'ai_crawler', /timpibot/i],\n // https://knownagents.com/agents/ai2bot\n ['AI2Bot', 'ai_crawler', /ai2bot/i],\n // https://knownagents.com/agents/pangubot\n ['PanguBot', 'ai_crawler', /pangubot/i],\n // https://knownagents.com/agents/tiktokspider\n ['TikTokSpider', 'ai_crawler', /tiktokspider/i],\n // https://knownagents.com/agents/deepseekbot\n ['DeepSeekBot', 'ai_crawler', /deepseekbot/i],\n // https://knownagents.com/agents/doubaobot\n ['DoubaoBot', 'ai_crawler', /doubaobot/i],\n // https://knownagents.com/agents/erniebot\n ['ERNIEBot', 'ai_crawler', /erniebot/i],\n // https://knownagents.com/agents/qwenbot\n ['QwenBot', 'ai_crawler', /qwenbot/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['KimiBot', 'ai_crawler', /kimibot/i],\n // https://knownagents.com/agents/chatglm-spider\n ['ChatGLM-Spider', 'ai_crawler', /chatglm-spider/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-Training', 'ai_crawler', /mistralai-training/i],\n // https://knownagents.com/agents/yandexadditional\n ['YandexAdditional', 'ai_crawler', /yandexadditional/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-Extended', 'ai_crawler', /google-extended/i],\n // https://docs.aws.amazon.com/kendra/latest/dg/what-is-kendra.html\n ['Amazon Kendra', 'ai_crawler', /amazon-kendra|kendrabot/i],\n // https://knownagents.com/agents/bedrockbot\n ['bedrockbot', 'ai_crawler', /bedrockbot/i],\n // https://brightdata.com/brightbot\n ['Brightbot', 'ai_crawler', /brightbot/i],\n // https://firecrawl.dev\n ['FirecrawlAgent', 'ai_crawler', /firecrawl/i],\n // https://github.com/unclecode/crawl4ai\n ['Crawl4AI', 'ai_crawler', /crawl4ai/i],\n // https://apify.com/apify/website-content-crawler\n ['ApifyBot', 'ai_crawler', /apify/i],\n // https://github.com/rom1504/img2dataset\n ['img2dataset', 'ai_crawler', /img2dataset/i],\n // https://knownagents.com/agents/laion-huggingface-processor\n ['LAION', 'ai_crawler', /laion/i],\n // https://developers.cloudflare.com/browser-rendering/\n ['Cloudflare Browser Rendering', 'ai_crawler', /cloudflarebrowserrendering/i],\n\n // link previews\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['facebookexternalhit', 'link_preview', /facebookexternalhit/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Facebot', 'link_preview', /facebot/i],\n // https://developer.x.com/en/docs/x-for-websites/cards/guides/getting-started\n ['Twitterbot', 'link_preview', /twitterbot/i],\n // https://www.linkedin.com/help/linkedin/answer/a521928\n ['LinkedInBot', 'link_preview', /linkedinbot/i],\n // https://api.slack.com/robots\n ['Slackbot', 'link_preview', /slackbot|slack-imgproxy/i],\n // https://discord.com\n ['Discordbot', 'link_preview', /discordbot/i],\n // https://core.telegram.org/bots\n ['TelegramBot', 'link_preview', /telegrambot/i],\n // https://www.whatsapp.com\n ['WhatsApp', 'link_preview', /^whatsapp\\//i],\n // https://www.pinterest.com/bot.html\n ['Pinterestbot', 'link_preview', /pinterestbot|^pinterest\\/0\\./i],\n // https://www.reddit.com\n ['redditbot', 'link_preview', /redditbot/i],\n // https://developers.snap.com/robots\n ['Snap URL Preview', 'link_preview', /snap url preview/i],\n // https://knownagents.com/agents/skypeuripreview\n ['SkypeUriPreview', 'link_preview', /skypeuripreview/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['BingPreview', 'link_preview', /bingpreview|microsoftpreview/i],\n // https://iframely.com/docs/about\n ['Iframely', 'link_preview', /iframely/i],\n // https://embed.ly\n ['Embedly', 'link_preview', /embedly/i],\n // https://devtalk.kakao.com/t/scrap/33984\n ['KakaoTalk-scrap', 'link_preview', /kakaotalk-scrap/i],\n // https://vk.com/dev/Share\n ['vkShare', 'link_preview', /vkshare/i],\n // https://www.viber.com\n ['Viber', 'link_preview', /^viber\\b|viber-crawler/i],\n // https://github.com/bluesky-social/indigo\n ['Bluesky Cardyb', 'link_preview', /cardyb/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-PageRenderer', 'link_preview', /google-pagerenderer/i],\n // https://vercel.com\n ['vercel-screenshot', 'link_preview', /vercel-screenshot/i],\n\n // SEO, marketing and page-speed tools; before the search crawlers, Lighthouse and the\n // Search Console tester borrow Google's name\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-InspectionTool', 'seo_tool', /google-inspectiontool/i],\n // https://developer.chrome.com/docs/lighthouse\n ['Lighthouse', 'seo_tool', /chrome-lighthouse|google page speed insights/i],\n // https://gtmetrix.com\n ['GTmetrix', 'seo_tool', /gtmetrix/i],\n // https://ahrefs.com/robot\n ['AhrefsBot', 'seo_tool', /ahrefs(?:bot|siteaudit)/i],\n // https://www.semrush.com/bot/\n ['SemrushBot', 'seo_tool', /semrush/i],\n // https://mj12bot.com\n ['MJ12bot', 'seo_tool', /mj12bot/i],\n // https://moz.com/help/moz-procedures/crawlers/dotbot\n ['DotBot', 'seo_tool', /dotbot/i],\n // https://moz.com/help/moz-procedures/crawlers/rogerbot\n ['rogerbot', 'seo_tool', /rogerbot/i],\n // https://www.screamingfrog.co.uk/seo-spider/\n ['Screaming Frog', 'seo_tool', /screaming frog/i],\n // https://serpstatbot.com\n ['SerpstatBot', 'seo_tool', /serpstatbot/i],\n // https://webmeup-crawler.com\n ['BLEXBot', 'seo_tool', /blexbot/i],\n // https://dataforseo.com/dataforseo-bot\n ['DataForSeoBot', 'seo_tool', /dataforseobot/i],\n // https://knownagents.com/agents/hubspot-crawler\n ['HubSpot', 'seo_tool', /hubspot/i],\n // https://search.google.com/structured-data/testing-tool\n ['Google-Structured-Data-Testing-Tool', 'seo_tool', /google-structured-data-testing-tool/i],\n // https://www.webpagetest.org\n ['WebPageTest', 'seo_tool', /\\bptst\\/\\d/i],\n // https://www.dareboost.com\n ['DareBoost', 'seo_tool', /dareboost/i],\n // https://www.exensa.com/crawl\n ['Barkrowler', 'seo_tool', /barkrowler/i],\n // https://seranking.com/backlinks-crawler\n ['SE Ranking', 'seo_tool', /seranking|sebot-wa/i],\n // https://www.brightedge.com\n ['BrightEdge', 'seo_tool', /brightedge/i],\n // https://searchatlas.com\n ['SearchAtlas', 'seo_tool', /searchatlas/i],\n // https://www.siteimprove.com\n ['Siteimprove', 'seo_tool', /siteimprove/i],\n // https://www.dataprovider.com\n ['Dataprovider', 'seo_tool', /dataprovider\\.com/i],\n // https://www.meltwater.com\n ['Meltwater', 'seo_tool', /meltwater/i],\n // https://awario.com/bots.html\n ['Awario', 'seo_tool', /awario/i],\n\n // search engines\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Googlebot', 'search_crawler', /googlebot/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Storebot-Google', 'search_crawler', /storebot-google/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['GoogleOther', 'search_crawler', /googleother/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['Bingbot', 'search_crawler', /bingbot/i],\n // https://support.apple.com/en-us/119829\n ['Applebot', 'search_crawler', /applebot/i],\n // https://www.baidu.com/search/spider.html\n ['Baiduspider', 'search_crawler', /baiduspider/i],\n // https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html\n ['YandexBot', 'search_crawler', /yandex(?:\\w*bot|images|metrika)/i],\n // https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot\n ['DuckDuckBot', 'search_crawler', /duckduckbot/i],\n // https://help.yahoo.com/kb/SLN22600.html\n ['Yahoo Slurp', 'search_crawler', /yahoo!?[\\s/]*slurp/i],\n // https://www.sogou.com/docs/help/webmasters.htm#07\n ['Sogou', 'search_crawler', /sogou[\\w\\s-]*spider/i],\n // https://www.so.com/help/help_3_2.html\n ['360Spider', 'search_crawler', /360spider|haosouspider/i],\n // https://knownagents.com/agents/yisouspider\n ['YisouSpider', 'search_crawler', /yisouspider/i],\n // https://webmaster.petalsearch.com/site/petalbot\n ['PetalBot', 'search_crawler', /petalbot/i],\n // https://napoveda.seznam.cz/en/seznambot-intro/\n ['SeznamBot', 'search_crawler', /seznambot/i],\n // https://knownagents.com/agents/yeti\n ['Yeti', 'search_crawler', /\\byeti\\//i],\n // https://help2.line.me/linesearchbot/web/?contentId=50006055&lang=en\n ['Linespider', 'search_crawler', /linespider/i],\n // https://help.qwant.com/bot/\n ['Qwantbot', 'search_crawler', /qwant(?:bot|ify)/i],\n // https://help.coccoc.com/searchengine\n ['coccocbot', 'search_crawler', /coccocbot/i],\n // https://www.mojeek.com/bot.html\n ['MojeekBot', 'search_crawler', /mojeekbot/i],\n // https://search.brave.com/help/brave-search-crawler\n ['Bravebot', 'search_crawler', /bravebot/i],\n // https://bot.seekport.com\n ['SeekportBot', 'search_crawler', /seekport/i],\n // https://mwmbl.org\n ['mwmbl', 'search_crawler', /mwmbl/i],\n // https://archive.org/details/archive.org_bot\n ['Internet Archive', 'search_crawler', /archive\\.org_bot|ia_archiver|archive-it|archiveteam/i],\n\n // monitoring, synthetics, security and consent scanners, service callers\n // https://www.pingdom.com\n ['Pingdom', 'monitoring', /pingdom/i],\n // https://uptimerobot.com\n ['UptimeRobot', 'monitoring', /uptimerobot/i],\n // https://www.statuscake.com\n ['StatusCake', 'monitoring', /statuscake/i],\n // https://www.site24x7.com\n ['Site24x7', 'monitoring', /site24x7/i],\n // https://betterstack.com/docs/uptime/\n ['Better Stack', 'monitoring', /better ?uptime|betterstack/i],\n // https://docs.datadoghq.com/synthetics/\n ['Datadog', 'monitoring', /datadog/i],\n // https://www.checklyhq.com/docs/\n ['Checkly', 'monitoring', /checkly/i],\n // https://docs.newrelic.com/docs/synthetics/\n ['NewRelicPinger', 'monitoring', /newrelicpinger/i],\n // https://github.com/louislam/uptime-kuma\n ['Uptime-Kuma', 'monitoring', /uptime-kuma/i],\n // https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/\n ['Grafana Synthetic Monitoring', 'monitoring', /grafanasyntheticmonitoring/i],\n // https://docs.dynatrace.com/docs/observe/digital-experience/synthetic-monitoring\n ['Dynatrace', 'monitoring', /ruxitsynthetic|dynatrace/i],\n // https://docs.splunk.com/observability/en/synthetics/intro-synthetics.html\n ['Splunk', 'monitoring', /splunk/i],\n // https://www.catchpoint.com\n ['Catchpoint', 'monitoring', /catchpoint/i],\n // https://ghostinspector.com\n ['Ghost Inspector', 'monitoring', /ghost inspector/i],\n // https://docs.digitalocean.com/products/uptime/\n ['DigitalOcean Uptime', 'monitoring', /digitalocean uptime/i],\n // https://ohdear.app/docs/faq/what-is-the-oh-dear-checker\n ['OhDear', 'monitoring', /ohdear/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['Google-Safety', 'monitoring', /google-safety/i],\n // https://www.cookiebot.com\n ['Cookiebot', 'monitoring', /cookiebot/i],\n // https://knownagents.com/agents/onetrust-cmp-scanner\n ['OneTrust', 'monitoring', /onetrust/i],\n // https://www.cookiehub.com\n ['CookieHub', 'monitoring', /cookiehub/i],\n // https://detectify.com/bot/\n ['Detectify', 'monitoring', /detectify/i],\n // https://about.censys.io\n ['CensysInspect', 'monitoring', /censysinspect/i],\n // https://www.bitsight.com\n ['BitSightBot', 'monitoring', /bitsightbot/i],\n // https://github.com/zmap/zgrab2\n ['zgrab', 'monitoring', /zgrab/i],\n // https://nmap.org/book/nse.html\n ['Nmap', 'monitoring', /nmap scripting engine/i],\n // https://docs.stripe.com/webhooks\n ['Stripe', 'monitoring', /stripe\\/1\\.0|stripebot|merchantsecurityscanner/i],\n\n // scripted browsers\n // https://developer.chrome.com/docs/chromium/headless\n ['HeadlessChrome', 'headless_browser', /headlesschrome/i],\n // https://phantomjs.org\n ['PhantomJS', 'headless_browser', /phantomjs/i],\n // https://slimerjs.org\n ['SlimerJS', 'headless_browser', /slimerjs/i],\n // https://playwright.dev\n ['Playwright', 'headless_browser', /playwright/i],\n // https://pptr.dev\n ['Puppeteer', 'headless_browser', /puppeteer/i],\n // https://www.selenium.dev\n ['Selenium', 'headless_browser', /selenium/i],\n // https://www.cypress.io\n ['Cypress', 'headless_browser', /cypress/i],\n // https://lightpanda.io\n ['Lightpanda', 'headless_browser', /lightpanda/i],\n // https://wkhtmltopdf.org\n ['wkhtmltopdf', 'headless_browser', /wkhtmltopdf/i],\n\n // libraries and command-line clients\n // https://curl.se\n ['curl', 'http_client', /^curl\\//i],\n // https://www.gnu.org/software/wget/\n ['Wget', 'http_client', /^wget\\//i],\n // https://requests.readthedocs.io\n ['python-requests', 'http_client', /python-requests/i],\n // https://docs.python.org/3/library/urllib.request.html\n ['python-urllib', 'http_client', /python-urllib/i],\n // https://docs.aiohttp.org\n ['aiohttp', 'http_client', /aiohttp/i],\n // https://www.python-httpx.org\n ['httpx', 'http_client', /python-httpx|^httpx\\//i],\n // https://scrapy.org\n ['Scrapy', 'http_client', /scrapy/i],\n // https://pkg.go.dev/net/http\n ['Go-http-client', 'http_client', /go-http-client/i],\n // https://github.com/square/okhttp\n ['okhttp', 'http_client', /^okhttp\\//i],\n // https://hc.apache.org/httpcomponents-client-5.5.x/\n ['Java', 'http_client', /^java\\/|apache-httpclient/i],\n // https://axios-http.com\n ['axios', 'http_client', /^axios\\//i],\n // https://github.com/node-fetch/node-fetch\n ['node-fetch', 'http_client', /node-fetch/i],\n // https://undici.nodejs.org\n ['undici', 'http_client', /^undici/i],\n // https://www.postman.com\n ['PostmanRuntime', 'http_client', /postmanruntime/i],\n // https://insomnia.rest\n ['insomnia', 'http_client', /^insomnia\\//i],\n // https://metacpan.org/pod/LWP\n ['libwww-perl', 'http_client', /libwww-perl/i],\n // https://docs.guzzlephp.org\n ['Guzzle', 'http_client', /guzzlehttp/i],\n // https://developers.google.com/apps-script/reference/url-fetch\n ['Google-Apps-Script', 'http_client', /google-apps-script/i],\n // https://support.google.com/docs/answer/3093339\n ['GoogleDocs', 'http_client', /googledocs/i],\n] as const satisfies readonly (readonly [string, BotCategory, RegExp])[];\n\nconst botishToken =\n /\\b([\\w.-]*?(?:bot|crawler|spider|scraper|fetcher|agent|preview|checker|monitor)[\\w-]*)\\b/i;\nconst botishWord = /^(?:bot|crawler|spider|scraper|fetcher|agent|preview|checker|monitor)$/i;\nconst compatibleToken = /compatible;\\s*([a-z][\\w.-]*(?: [a-z][\\w.-]*)?)/i;\nconst productTokens = /([a-z][\\w.-]*)\\/\\d/gi;\nconst browserToken =\n /^(?:mozilla|applewebkit|khtml|gecko|chrome|chromium|safari|version|mobile|firefox|edg|edge|opr|msie|trident)$/i;\n\n/**\n * A name for a bot that is not in the named table, from the first of: a token that sounds like\n * one (`Bytespider`, `ABEvalBot`), the name after `compatible;` (`Google-Read-Aloud`), a product\n * token that is not a browser's (`Barkrowler/0.5`), what the generic pattern matched. URLs and\n * email addresses are dropped first, as nearly every crawler links its docs.\n */\nexport function nameOfUnknownBot(userAgent: string, matched: string): string {\n const text = userAgent\n .replace(/\\+?https?:\\/\\/\\S+/gi, ' ')\n .replace(/[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+/g, ' ');\n\n const botish = botishToken.exec(text)?.[1];\n if (botish && !botishWord.test(botish)) return botish.slice(0, 64);\n\n const compatible = compatibleToken.exec(text)?.[1];\n if (compatible && !browserToken.test(compatible)) return compatible.slice(0, 64);\n\n for (const [, product] of text.matchAll(productTokens)) {\n if (!browserToken.test(product)) return product.slice(0, 64);\n }\n\n return matched.replace(/^\\W+|\\W+$/g, '').slice(0, 64) || 'unknown';\n}\n\n/**\n * Whether a web visitor is a bot, which one, and what kind. Run on the server when the visitor\n * is created, with the tags it was created with: the user agent is the request's header\n * (`tags.user_agent`, which the server writes), not anything the client says about itself, so\n * the verdict can be recomputed from stored tags when the rules change.\n *\n * Call it for web visitors only: a native app's requests carry an HTTP library's user agent\n * (CFNetwork, okhttp) that would read as a bot, and no crawler runs the app.\n *\n * In order: a bot we can name; a browser driven by WebDriver (`tags.webdriver`, which the SDK\n * sets from `navigator.webdriver`, the one sign a scripted browser with a normal user agent\n * gives); anything the generic pattern calls automated; no user agent at all.\n */\nexport function botOf(tags: TrackTags): Bot {\n const userAgent = typeof tags.user_agent === 'string' ? tags.user_agent.trim() : '';\n\n for (const [name, category, pattern] of NAMED_BOTS) {\n if (pattern.test(userAgent)) return { is_bot: true, bot_name: name, bot_category: category };\n }\n\n const generic = userAgent ? GENERIC_BOT.exec(userAgent) : null;\n const unknownName = generic ? nameOfUnknownBot(userAgent, generic[0]) : null;\n\n // A scripted browser that says so in its user agent takes that name, else it is just WebDriver.\n if (tags.webdriver === true) {\n return { is_bot: true, bot_name: unknownName ?? 'WebDriver', bot_category: 'headless_browser' };\n }\n\n if (unknownName) return { is_bot: true, bot_name: unknownName, bot_category: 'other' };\n\n if (!userAgent)\n return { is_bot: true, bot_name: '(no user agent)', bot_category: 'no_user_agent' };\n\n return NOT_A_BOT;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/bot/index.ts"],"sourcesContent":["import type { TrackTags } from '../track/types';\nimport { GENERIC_BOT } from './generic';\n\n/**\n * What kind of automated visitor a bot is, as the analytics tools that report bots separately\n * group them (PostHog's traffic categories, Cloudflare's verified bot categories, Matomo's\n * DeviceDetector). Stored next to the name so dashboards can group without re-deriving:\n *\n * - search_crawler: indexes pages for a search engine (Googlebot, Bingbot, Baiduspider)\n * - ai_crawler: collects content to train models (GPTBot, ClaudeBot, Meta-ExternalAgent)\n * - ai_search: indexes pages for an AI search product (OAI-SearchBot, PerplexityBot)\n * - ai_assistant: fetches a page because a person asked an assistant to (ChatGPT-User)\n * - advertising: works for an ad system — reviews landing pages, targets or verifies ads\n * (Meta-ExternalAds, AdsBot-Google, Mediapartners-Google)\n * - link_preview: renders the card of a link shared in a feed or a chat (facebookexternalhit)\n * - seo_tool: SEO, marketing and page-speed tools (AhrefsBot, Lighthouse, HubSpot)\n * - monitoring: uptime checks, synthetics and service callers (Pingdom, Stripe)\n * - headless_browser: a scripted browser (HeadlessChrome, Playwright, a WebDriver session)\n * - http_client: a library or command-line client (curl, python-requests)\n * - no_user_agent: a request without a user agent, which no browser sends\n * - other: automated by every sign, but none of the above\n */\nexport const BOT_CATEGORIES = [\n 'search_crawler',\n 'ai_crawler',\n 'ai_search',\n 'ai_assistant',\n 'advertising',\n 'link_preview',\n 'seo_tool',\n 'monitoring',\n 'headless_browser',\n 'http_client',\n 'no_user_agent',\n 'other',\n] as const;\n\nexport type BotCategory = (typeof BOT_CATEGORIES)[number];\n\n/**\n * The verdict, shaped like the columns a product stores it in (`is_bot`, `bot_name`,\n * `bot_category`). A person is `{ is_bot: false, bot_name: null, bot_category: null }`.\n */\nexport type Bot =\n | { is_bot: true; bot_name: string; bot_category: BotCategory }\n | { is_bot: false; bot_name: null; bot_category: null };\n\nexport const NOT_A_BOT: Bot = { is_bot: false, bot_name: null, bot_category: null };\n\n/**\n * Bots we can name, as `[name, category, pattern]`, tried in order; the first match wins.\n *\n * Where the list comes from (checked 2026-09-30):\n * - bowser's bot parsers (the ~25 named bots its `platform.type === 'bot'` reports), which this\n * replaces.\n * - PostHog's `bot_definitions.py` (web analytics traffic classification), for the bots and\n * categories an analytics product sees most.\n * - ai.robots.txt (`robots.json`), for AI crawlers, search bots, assistants and agents.\n * - The operators' own docs for the big ones: Google's crawler list, OpenAI's and Anthropic's\n * bot pages, Meta's web crawlers, Perplexity, Bing, Apple.\n * - Bots seen in production (Meta-ExternalAds, HubSpot, Bytespider).\n * Every entry was run against the real user agents in crawler-user-agents and PostHog's\n * fixtures, and bowser's browser fixtures were run to check no browser is taken for a bot\n * (Sogou's browser against its spider, Pinterest's in-app browser against its bot); see\n * `index.test.ts` for where to get them.\n *\n * The link above each entry is the operator's page about the bot, else its product page, else\n * its Known Agents profile (knownagents.com, formerly Dark Visitors) when the operator has none.\n *\n * Names are the operators' spelling of their user agent token. Order matters where one token\n * contains another or borrows a name: advertising and SEO tools come before the search engines\n * whose names they carry, and the more specific of Meta's, Anthropic's and Perplexity's tokens\n * come first. The long tail is left to the generic pattern, filed as `other` and named by\n * `nameOfUnknownBot`; add a bot here when it is worth its own category or name in a dashboard.\n */\nexport const NAMED_BOTS = [\n // advertising: before the search crawlers, AdsBot and Mediapartners carry Google's name\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalAds', 'advertising', /meta-externalads/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['facebookcatalog', 'advertising', /facebookcatalog/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['AdsBot-Google', 'advertising', /adsbot-google/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['Mediapartners-Google', 'advertising', /mediapartners-google/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['AdIdxBot', 'advertising', /adidxbot/i],\n // https://support.google.com/adwords/answer/2404197\n ['Google-AdWords', 'advertising', /google-adwords/i],\n // https://support.google.com/google-ads/answer/6095821\n ['Google-Ads-Conversions', 'advertising', /google-ads-conversions/i],\n // https://developers.openai.com/api/docs/bots\n ['OAI-AdsBot', 'advertising', /oai-adsbot/i],\n // https://businesshelp.snapchat.com/s/article/adsbot-crawler\n ['SnapchatAds', 'advertising', /snapchatads/i],\n // https://www.taboola.com\n ['Taboolabot', 'advertising', /taboolabot/i],\n\n // AI assistants and agents: a person asked for this page\n // https://developers.openai.com/api/docs/bots\n ['ChatGPT-User', 'ai_assistant', /chatgpt-user/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-User', 'ai_assistant', /claude-user/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-Web', 'ai_assistant', /claude-web/i],\n // https://docs.perplexity.ai/guides/bots\n ['Perplexity-User', 'ai_assistant', /perplexity-user/i],\n // https://duckduckgo.com/duckduckgo-help-pages/results/duckassistbot\n ['DuckAssistBot', 'ai_assistant', /duckassistbot/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalFetcher', 'ai_assistant', /meta-externalfetcher/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-User', 'ai_assistant', /mistralai-user/i],\n // https://knownagents.com/agents/manus-user\n ['Manus-User', 'ai_assistant', /manus-user/i],\n // https://knownagents.com/agents/shap-user\n ['Shap-User', 'ai_assistant', /shap-user/i],\n // https://quillbot.com\n ['QuillBot', 'ai_assistant', /quillbot/i],\n // https://developer.amazon.com/amazonbot\n ['Amzn-User', 'ai_assistant', /amzn-user/i],\n // https://knownagents.com/agents/amazon-qbusiness\n ['amazon-QBusiness', 'ai_assistant', /amazon-qbusiness/i],\n // https://docs.aws.amazon.com/bedrock-agentcore/\n ['Amazon-Bedrock-AgentCore-Browser', 'ai_assistant', /amazon-bedrock-agentcore/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-Agent', 'ai_assistant', /google-?agent/i],\n // https://gemini.google/overview/deep-research/\n ['Gemini-Deep-Research', 'ai_assistant', /gemini-deep-research/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-NotebookLM', 'ai_assistant', /google-notebooklm/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['Kimi-User', 'ai_assistant', /kimi-(?:user|agent)/i],\n // https://knownagents.com/agents/tongyibot\n ['TongyiBot', 'ai_assistant', /tongyibot/i],\n // https://knownagents.com/agents/yiyanbot\n ['YiyanBot', 'ai_assistant', /yiyanbot/i],\n // https://help.kagi.com/kagi/ai/kagi-ai.html\n ['kagi-fetcher', 'ai_assistant', /kagi-fetcher/i],\n // https://devin.ai\n ['Devin', 'ai_assistant', /\\bdevin\\/\\d/i],\n // https://knownagents.com/agents/novaact\n ['NovaAct', 'ai_assistant', /novaact/i],\n\n // AI search\n // https://developers.openai.com/api/docs/bots\n ['OAI-SearchBot', 'ai_search', /oai-searchbot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['Claude-SearchBot', 'ai_search', /claude-searchbot/i],\n // https://docs.perplexity.ai/guides/bots\n ['PerplexityBot', 'ai_search', /perplexitybot/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-WebIndexer', 'ai_search', /meta-webindexer/i],\n // https://developer.amazon.com/amazonbot\n ['Amazonbot', 'ai_search', /amazonbot/i],\n // https://knownagents.com/agents/youbot\n ['YouBot', 'ai_search', /youbot/i],\n // https://knownagents.com/agents/phindbot\n ['PhindBot', 'ai_search', /phindbot/i],\n // https://developer.amazon.com/amazonbot\n ['Amzn-SearchBot', 'ai_search', /amzn-searchbot/i],\n // https://knownagents.com/agents/azureai-searchbot\n ['AzureAI-SearchBot', 'ai_search', /azureai-searchbot/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['Kimi-SearchBot', 'ai_search', /kimi-searchbot/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-Index', 'ai_search', /mistralai-index/i],\n // https://knownagents.com/agents/exasearchbot\n ['ExaSearchBot', 'ai_search', /exasearchbot|\\bexabot/i],\n // https://knownagents.com/agents/tavilybot\n ['TavilyBot', 'ai_search', /tavilybot/i],\n // https://linkup.so/bot\n ['LinkupBot', 'ai_search', /linkupbot/i],\n // https://knownagents.com/agents/iaskspider\n ['iAskBot', 'ai_search', /iask(?:bot|spider)/i],\n ['Andibot', 'ai_search', /andibot/i],\n // https://developers.cloudflare.com/autorag\n ['Cloudflare-AutoRAG', 'ai_search', /cloudflare-autorag/i],\n // https://docs.parallel.ai/resources/crawler\n ['ShapBot', 'ai_search', /shapbot/i],\n\n // AI training\n // https://developers.openai.com/api/docs/bots\n ['GPTBot', 'ai_crawler', /gptbot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['ClaudeBot', 'ai_crawler', /claudebot/i],\n // https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler\n ['anthropic-ai', 'ai_crawler', /anthropic-ai/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Meta-ExternalAgent', 'ai_crawler', /meta-externalagent/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['FacebookBot', 'ai_crawler', /facebookbot/i],\n // https://knownagents.com/agents/bytespider\n ['Bytespider', 'ai_crawler', /bytespider/i],\n // https://commoncrawl.org/ccbot\n ['CCBot', 'ai_crawler', /ccbot/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-CloudVertexBot', 'ai_crawler', /google-cloudvertexbot/i],\n // https://knownagents.com/agents/cohere-training-data-crawler\n ['cohere-ai', 'ai_crawler', /cohere-(?:ai|training-data-crawler)/i],\n // https://www.diffbot.com/docs/crawl/faq/robots-txt\n ['Diffbot', 'ai_crawler', /diffbot/i],\n // https://knownagents.com/agents/webzio-extended\n ['Omgili', 'ai_crawler', /omgili|webzio-extended/i],\n // https://imagesift.com/about\n ['ImagesiftBot', 'ai_crawler', /imagesiftbot/i],\n // https://www.timpi.io\n ['Timpibot', 'ai_crawler', /timpibot/i],\n // https://knownagents.com/agents/ai2bot\n ['AI2Bot', 'ai_crawler', /ai2bot/i],\n // https://knownagents.com/agents/pangubot\n ['PanguBot', 'ai_crawler', /pangubot/i],\n // https://knownagents.com/agents/promptingbot\n ['PromptingBot', 'ai_crawler', /promptingbot/i],\n // https://knownagents.com/agents/reflectionbot\n ['Reflectionbot', 'ai_crawler', /reflectionbot/i],\n // https://knownagents.com/agents/tiktokspider\n ['TikTokSpider', 'ai_crawler', /tiktokspider/i],\n // https://knownagents.com/agents/deepseekbot\n ['DeepSeekBot', 'ai_crawler', /deepseekbot/i],\n // https://knownagents.com/agents/doubaobot\n ['DoubaoBot', 'ai_crawler', /doubaobot/i],\n // https://knownagents.com/agents/erniebot\n ['ERNIEBot', 'ai_crawler', /erniebot/i],\n // https://knownagents.com/agents/qwenbot\n ['QwenBot', 'ai_crawler', /qwenbot/i],\n // https://www.kimi.ai/policies/kimi-crawlers\n ['KimiBot', 'ai_crawler', /kimibot/i],\n // https://knownagents.com/agents/chatglm-spider\n ['ChatGLM-Spider', 'ai_crawler', /chatglm-spider/i],\n // https://docs.mistral.ai/robots\n ['MistralAI-Training', 'ai_crawler', /mistralai-training/i],\n // https://knownagents.com/agents/yandexadditional\n ['YandexAdditional', 'ai_crawler', /yandexadditional/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-Extended', 'ai_crawler', /google-extended/i],\n // https://docs.aws.amazon.com/kendra/latest/dg/what-is-kendra.html\n ['Amazon Kendra', 'ai_crawler', /amazon-kendra|kendrabot/i],\n // https://knownagents.com/agents/bedrockbot\n ['bedrockbot', 'ai_crawler', /bedrockbot/i],\n // https://brightdata.com/brightbot\n ['Brightbot', 'ai_crawler', /brightbot/i],\n // https://firecrawl.dev\n ['FirecrawlAgent', 'ai_crawler', /firecrawl/i],\n // https://github.com/unclecode/crawl4ai\n ['Crawl4AI', 'ai_crawler', /crawl4ai/i],\n // https://apify.com/apify/website-content-crawler\n ['ApifyBot', 'ai_crawler', /apify/i],\n // https://github.com/rom1504/img2dataset\n ['img2dataset', 'ai_crawler', /img2dataset/i],\n // https://knownagents.com/agents/laion-huggingface-processor\n ['LAION', 'ai_crawler', /laion/i],\n // https://developers.cloudflare.com/browser-rendering/\n ['Cloudflare Browser Rendering', 'ai_crawler', /cloudflarebrowserrendering/i],\n\n // link previews\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['facebookexternalhit', 'link_preview', /facebookexternalhit/i],\n // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers\n ['Facebot', 'link_preview', /facebot/i],\n // https://developer.x.com/en/docs/x-for-websites/cards/guides/getting-started\n ['Twitterbot', 'link_preview', /twitterbot/i],\n // https://www.linkedin.com/help/linkedin/answer/a521928\n ['LinkedInBot', 'link_preview', /linkedinbot/i],\n // https://api.slack.com/robots\n ['Slackbot', 'link_preview', /slackbot|slack-imgproxy/i],\n // https://discord.com\n ['Discordbot', 'link_preview', /discordbot/i],\n // https://core.telegram.org/bots\n ['TelegramBot', 'link_preview', /telegrambot/i],\n // https://www.whatsapp.com\n ['WhatsApp', 'link_preview', /^whatsapp\\//i],\n // https://www.pinterest.com/bot.html\n ['Pinterestbot', 'link_preview', /pinterestbot|^pinterest\\/0\\./i],\n // https://www.reddit.com\n ['redditbot', 'link_preview', /redditbot/i],\n // https://developers.snap.com/robots\n ['Snap URL Preview', 'link_preview', /snap url preview/i],\n // https://knownagents.com/agents/skypeuripreview\n ['SkypeUriPreview', 'link_preview', /skypeuripreview/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['BingPreview', 'link_preview', /bingpreview|microsoftpreview/i],\n // https://iframely.com/docs/about\n ['Iframely', 'link_preview', /iframely/i],\n // https://embed.ly\n ['Embedly', 'link_preview', /embedly/i],\n // https://devtalk.kakao.com/t/scrap/33984\n ['KakaoTalk-scrap', 'link_preview', /kakaotalk-scrap/i],\n // https://vk.com/dev/Share\n ['vkShare', 'link_preview', /vkshare/i],\n // https://www.viber.com\n ['Viber', 'link_preview', /^viber\\b|viber-crawler/i],\n // https://github.com/bluesky-social/indigo\n ['Bluesky Cardyb', 'link_preview', /cardyb/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers\n ['Google-PageRenderer', 'link_preview', /google-pagerenderer/i],\n // https://vercel.com\n ['vercel-screenshot', 'link_preview', /vercel-screenshot/i],\n\n // SEO, marketing and page-speed tools; before the search crawlers, Lighthouse and the\n // Search Console tester borrow Google's name\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Google-InspectionTool', 'seo_tool', /google-inspectiontool/i],\n // https://developer.chrome.com/docs/lighthouse\n ['Lighthouse', 'seo_tool', /chrome-lighthouse|google page speed insights/i],\n // https://gtmetrix.com\n ['GTmetrix', 'seo_tool', /gtmetrix/i],\n // https://ahrefs.com/robot\n ['AhrefsBot', 'seo_tool', /ahrefs(?:bot|siteaudit)/i],\n // https://www.semrush.com/bot/\n ['SemrushBot', 'seo_tool', /semrush/i],\n // https://mj12bot.com\n ['MJ12bot', 'seo_tool', /mj12bot/i],\n // https://moz.com/help/moz-procedures/crawlers/dotbot\n ['DotBot', 'seo_tool', /dotbot/i],\n // https://moz.com/help/moz-procedures/crawlers/rogerbot\n ['rogerbot', 'seo_tool', /rogerbot/i],\n // https://www.screamingfrog.co.uk/seo-spider/\n ['Screaming Frog', 'seo_tool', /screaming frog/i],\n // https://serpstatbot.com\n ['SerpstatBot', 'seo_tool', /serpstatbot/i],\n // https://webmeup-crawler.com\n ['BLEXBot', 'seo_tool', /blexbot/i],\n // https://dataforseo.com/dataforseo-bot\n ['DataForSeoBot', 'seo_tool', /dataforseobot/i],\n // https://knownagents.com/agents/hubspot-crawler\n ['HubSpot', 'seo_tool', /hubspot/i],\n // https://search.google.com/structured-data/testing-tool\n ['Google-Structured-Data-Testing-Tool', 'seo_tool', /google-structured-data-testing-tool/i],\n // https://www.webpagetest.org\n ['WebPageTest', 'seo_tool', /\\bptst\\/\\d/i],\n // https://www.dareboost.com\n ['DareBoost', 'seo_tool', /dareboost/i],\n // https://www.exensa.com/crawl\n ['Barkrowler', 'seo_tool', /barkrowler/i],\n // https://seranking.com/backlinks-crawler\n ['SE Ranking', 'seo_tool', /seranking|sebot-wa/i],\n // https://www.brightedge.com\n ['BrightEdge', 'seo_tool', /brightedge/i],\n // https://searchatlas.com\n ['SearchAtlas', 'seo_tool', /searchatlas/i],\n // https://www.siteimprove.com\n ['Siteimprove', 'seo_tool', /siteimprove/i],\n // https://www.dataprovider.com\n ['Dataprovider', 'seo_tool', /dataprovider\\.com/i],\n // https://www.meltwater.com\n ['Meltwater', 'seo_tool', /meltwater/i],\n // https://awario.com/bots.html\n ['Awario', 'seo_tool', /awario/i],\n\n // search engines\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Googlebot', 'search_crawler', /googlebot/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['Storebot-Google', 'search_crawler', /storebot-google/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers\n ['GoogleOther', 'search_crawler', /googleother/i],\n // https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0\n ['Bingbot', 'search_crawler', /bingbot/i],\n // https://support.apple.com/en-us/119829\n ['Applebot', 'search_crawler', /applebot/i],\n // https://www.baidu.com/search/spider.html\n ['Baiduspider', 'search_crawler', /baiduspider/i],\n // https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html\n ['YandexBot', 'search_crawler', /yandex(?:\\w*bot|images|metrika)/i],\n // https://duckduckgo.com/duckduckgo-help-pages/results/duckduckbot\n ['DuckDuckBot', 'search_crawler', /duckduckbot/i],\n // https://help.yahoo.com/kb/SLN22600.html\n ['Yahoo Slurp', 'search_crawler', /yahoo!?[\\s/]*slurp/i],\n // https://www.sogou.com/docs/help/webmasters.htm#07\n ['Sogou', 'search_crawler', /sogou[\\w\\s-]*spider/i],\n // https://www.so.com/help/help_3_2.html\n ['360Spider', 'search_crawler', /360spider|haosouspider/i],\n // https://knownagents.com/agents/yisouspider\n ['YisouSpider', 'search_crawler', /yisouspider/i],\n // https://webmaster.petalsearch.com/site/petalbot\n ['PetalBot', 'search_crawler', /petalbot/i],\n // https://napoveda.seznam.cz/en/seznambot-intro/\n ['SeznamBot', 'search_crawler', /seznambot/i],\n // https://knownagents.com/agents/yeti\n ['Yeti', 'search_crawler', /\\byeti\\//i],\n // https://help2.line.me/linesearchbot/web/?contentId=50006055&lang=en\n ['Linespider', 'search_crawler', /linespider/i],\n // https://help.qwant.com/bot/\n ['Qwantbot', 'search_crawler', /qwant(?:bot|ify)/i],\n // https://help.coccoc.com/searchengine\n ['coccocbot', 'search_crawler', /coccocbot/i],\n // https://www.mojeek.com/bot.html\n ['MojeekBot', 'search_crawler', /mojeekbot/i],\n // https://search.brave.com/help/brave-search-crawler\n ['Bravebot', 'search_crawler', /bravebot/i],\n // https://bot.seekport.com\n ['SeekportBot', 'search_crawler', /seekport/i],\n // https://mwmbl.org\n ['mwmbl', 'search_crawler', /mwmbl/i],\n // https://archive.org/details/archive.org_bot\n ['Internet Archive', 'search_crawler', /archive\\.org_bot|ia_archiver|archive-it|archiveteam/i],\n\n // monitoring, synthetics, security and consent scanners, service callers\n // https://www.pingdom.com\n ['Pingdom', 'monitoring', /pingdom/i],\n // https://uptimerobot.com\n ['UptimeRobot', 'monitoring', /uptimerobot/i],\n // https://www.statuscake.com\n ['StatusCake', 'monitoring', /statuscake/i],\n // https://www.site24x7.com\n ['Site24x7', 'monitoring', /site24x7/i],\n // https://betterstack.com/docs/uptime/\n ['Better Stack', 'monitoring', /better ?uptime|betterstack/i],\n // https://docs.datadoghq.com/synthetics/\n ['Datadog', 'monitoring', /datadog/i],\n // https://www.checklyhq.com/docs/\n ['Checkly', 'monitoring', /checkly/i],\n // https://docs.newrelic.com/docs/synthetics/\n ['NewRelicPinger', 'monitoring', /newrelicpinger/i],\n // https://github.com/louislam/uptime-kuma\n ['Uptime-Kuma', 'monitoring', /uptime-kuma/i],\n // https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/\n ['Grafana Synthetic Monitoring', 'monitoring', /grafanasyntheticmonitoring/i],\n // https://docs.dynatrace.com/docs/observe/digital-experience/synthetic-monitoring\n ['Dynatrace', 'monitoring', /ruxitsynthetic|dynatrace/i],\n // https://docs.splunk.com/observability/en/synthetics/intro-synthetics.html\n ['Splunk', 'monitoring', /splunk/i],\n // https://www.catchpoint.com\n ['Catchpoint', 'monitoring', /catchpoint/i],\n // https://ghostinspector.com\n ['Ghost Inspector', 'monitoring', /ghost inspector/i],\n // https://docs.digitalocean.com/products/uptime/\n ['DigitalOcean Uptime', 'monitoring', /digitalocean uptime/i],\n // https://ohdear.app/docs/faq/what-is-the-oh-dear-checker\n ['OhDear', 'monitoring', /ohdear/i],\n // https://developers.google.com/crawling/docs/crawlers-fetchers/google-special-case-crawlers\n ['Google-Safety', 'monitoring', /google-safety/i],\n // https://www.cookiebot.com\n ['Cookiebot', 'monitoring', /cookiebot/i],\n // https://knownagents.com/agents/onetrust-cmp-scanner\n ['OneTrust', 'monitoring', /onetrust/i],\n // https://www.cookiehub.com\n ['CookieHub', 'monitoring', /cookiehub/i],\n // https://detectify.com/bot/\n ['Detectify', 'monitoring', /detectify/i],\n // https://about.censys.io\n ['CensysInspect', 'monitoring', /censysinspect/i],\n // https://www.bitsight.com\n ['BitSightBot', 'monitoring', /bitsightbot/i],\n // https://github.com/zmap/zgrab2\n ['zgrab', 'monitoring', /zgrab/i],\n // https://nmap.org/book/nse.html\n ['Nmap', 'monitoring', /nmap scripting engine/i],\n // https://docs.stripe.com/webhooks\n ['Stripe', 'monitoring', /stripe\\/1\\.0|stripebot|merchantsecurityscanner/i],\n\n // scripted browsers\n // https://developer.chrome.com/docs/chromium/headless\n ['HeadlessChrome', 'headless_browser', /headlesschrome/i],\n // https://phantomjs.org\n ['PhantomJS', 'headless_browser', /phantomjs/i],\n // https://slimerjs.org\n ['SlimerJS', 'headless_browser', /slimerjs/i],\n // https://playwright.dev\n ['Playwright', 'headless_browser', /playwright/i],\n // https://pptr.dev\n ['Puppeteer', 'headless_browser', /puppeteer/i],\n // https://www.selenium.dev\n ['Selenium', 'headless_browser', /selenium/i],\n // https://www.cypress.io\n ['Cypress', 'headless_browser', /cypress/i],\n // https://lightpanda.io\n ['Lightpanda', 'headless_browser', /lightpanda/i],\n // https://wkhtmltopdf.org\n ['wkhtmltopdf', 'headless_browser', /wkhtmltopdf/i],\n\n // libraries and command-line clients\n // https://curl.se\n ['curl', 'http_client', /^curl\\//i],\n // https://www.gnu.org/software/wget/\n ['Wget', 'http_client', /^wget\\//i],\n // https://requests.readthedocs.io\n ['python-requests', 'http_client', /python-requests/i],\n // https://docs.python.org/3/library/urllib.request.html\n ['python-urllib', 'http_client', /python-urllib/i],\n // https://docs.aiohttp.org\n ['aiohttp', 'http_client', /aiohttp/i],\n // https://www.python-httpx.org\n ['httpx', 'http_client', /python-httpx|^httpx\\//i],\n // https://scrapy.org\n ['Scrapy', 'http_client', /scrapy/i],\n // https://pkg.go.dev/net/http\n ['Go-http-client', 'http_client', /go-http-client/i],\n // https://github.com/square/okhttp\n ['okhttp', 'http_client', /^okhttp\\//i],\n // https://hc.apache.org/httpcomponents-client-5.5.x/\n ['Java', 'http_client', /^java\\/|apache-httpclient/i],\n // https://axios-http.com\n ['axios', 'http_client', /^axios\\//i],\n // https://github.com/node-fetch/node-fetch\n ['node-fetch', 'http_client', /node-fetch/i],\n // https://undici.nodejs.org\n ['undici', 'http_client', /^undici/i],\n // https://www.postman.com\n ['PostmanRuntime', 'http_client', /postmanruntime/i],\n // https://insomnia.rest\n ['insomnia', 'http_client', /^insomnia\\//i],\n // https://metacpan.org/pod/LWP\n ['libwww-perl', 'http_client', /libwww-perl/i],\n // https://docs.guzzlephp.org\n ['Guzzle', 'http_client', /guzzlehttp/i],\n // https://developers.google.com/apps-script/reference/url-fetch\n ['Google-Apps-Script', 'http_client', /google-apps-script/i],\n // https://support.google.com/docs/answer/3093339\n ['GoogleDocs', 'http_client', /googledocs/i],\n] as const satisfies readonly (readonly [string, BotCategory, RegExp])[];\n\nconst botishToken =\n /\\b([\\w.-]*?(?:bot|crawler|spider|scraper|fetcher|agent|preview|checker|monitor)[\\w-]*)\\b/i;\nconst botishWord = /^(?:bot|crawler|spider|scraper|fetcher|agent|preview|checker|monitor)$/i;\nconst compatibleToken = /compatible;\\s*([a-z][\\w.-]*(?: [a-z][\\w.-]*)?)/i;\nconst productTokens = /([a-z][\\w.-]*)\\/\\d/gi;\nconst browserToken =\n /^(?:mozilla|applewebkit|khtml|gecko|chrome|chromium|safari|version|mobile|firefox|edg|edge|opr|msie|trident)$/i;\n\n/**\n * A name for a bot that is not in the named table, from the first of: a token that sounds like\n * one (`Bytespider`, `ABEvalBot`), the name after `compatible;` (`Google-Read-Aloud`), a product\n * token that is not a browser's (`Barkrowler/0.5`), what the generic pattern matched. URLs and\n * email addresses are dropped first, as nearly every crawler links its docs.\n */\nexport function nameOfUnknownBot(userAgent: string, matched: string): string {\n const text = userAgent\n .replace(/\\+?https?:\\/\\/\\S+/gi, ' ')\n .replace(/[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+/g, ' ');\n\n const botish = botishToken.exec(text)?.[1];\n if (botish && !botishWord.test(botish)) return botish.slice(0, 64);\n\n const compatible = compatibleToken.exec(text)?.[1];\n if (compatible && !browserToken.test(compatible)) return compatible.slice(0, 64);\n\n for (const [, product] of text.matchAll(productTokens)) {\n if (!browserToken.test(product)) return product.slice(0, 64);\n }\n\n return matched.replace(/^\\W+|\\W+$/g, '').slice(0, 64) || 'unknown';\n}\n\n/**\n * The request user agent of a page opened in Facebook's or Instagram's in-app browser when the\n * app sends the page's requests through its own network stack: `[FBAN/FB4A;FBAV/…]`,\n * `Instagram 445.0.0.34.44 (iPhone18,1; iOS 26_6_1; …) AppleWebKit/420+`. The page itself still\n * reads a browser's `navigator.userAgent`, which is why PostHog, GA4 and Matomo see a person.\n * isbot's generic pattern takes both for bots (a long token with no space, a product token that is\n * no browser's), so they are people here before it runs. Meta's ad prefetch loads only the HTML,\n * which runs no script and creates no visitor. The in-app browser's own user agent starts with\n * `Mozilla/5.0`, so the anchors leave it alone.\n */\nconst META_APP = /^\\[FBAN\\/|^Instagram \\d+(?:\\.\\d+)+ \\(/;\n\n/**\n * Whether a web visitor is a bot, which one, and what kind. Run on the server when the visitor\n * is created, with the tags it was created with: the user agent is the request's header\n * (`tags.user_agent`, which the server writes), not anything the client says about itself, so\n * the verdict can be recomputed from stored tags when the rules change.\n *\n * Call it for web visitors only: a native app's requests carry an HTTP library's user agent\n * (CFNetwork, okhttp) that would read as a bot, and no crawler runs the app.\n *\n * In order: a bot we can name; a browser driven by WebDriver (`tags.webdriver`, which the SDK\n * sets from `navigator.webdriver`, the one sign a scripted browser with a normal user agent\n * gives); a person in a Meta app (`META_APP`); anything the generic pattern calls automated; no\n * user agent at all.\n */\nexport function botOf(tags: TrackTags): Bot {\n const userAgent = typeof tags.user_agent === 'string' ? tags.user_agent.trim() : '';\n\n for (const [name, category, pattern] of NAMED_BOTS) {\n if (pattern.test(userAgent)) return { is_bot: true, bot_name: name, bot_category: category };\n }\n\n const generic = userAgent ? GENERIC_BOT.exec(userAgent) : null;\n const unknownName = generic ? nameOfUnknownBot(userAgent, generic[0]) : null;\n\n // A scripted browser that says so in its user agent takes that name, else it is just WebDriver.\n if (tags.webdriver === true) {\n return { is_bot: true, bot_name: unknownName ?? 'WebDriver', bot_category: 'headless_browser' };\n }\n\n if (META_APP.test(userAgent)) return NOT_A_BOT;\n\n if (unknownName) return { is_bot: true, bot_name: unknownName, bot_category: 'other' };\n\n if (!userAgent)\n return { is_bot: true, bot_name: '(no user agent)', bot_category: 'no_user_agent' };\n\n return NOT_A_BOT;\n}\n"],"mappings":"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"}
@@ -107,12 +107,14 @@ const tagsSchema = (0, zod_mini.object)({
107
107
  ko_click_id: (0, zod_mini.optional)((0, zod_mini.string)()),
108
108
  li_fat_id: (0, zod_mini.optional)((0, zod_mini.string)()),
109
109
  msclkid: (0, zod_mini.optional)((0, zod_mini.string)()),
110
- sccid: (0, zod_mini.optional)((0, zod_mini.string)()),
110
+ ScCid: (0, zod_mini.optional)((0, zod_mini.string)()),
111
111
  ttclid: (0, zod_mini.optional)((0, zod_mini.string)()),
112
112
  twclid: (0, zod_mini.optional)((0, zod_mini.string)()),
113
113
  wbraid: (0, zod_mini.optional)((0, zod_mini.string)()),
114
114
  gbraid: (0, zod_mini.optional)((0, zod_mini.string)()),
115
115
  yclid: (0, zod_mini.optional)((0, zod_mini.string)()),
116
+ oppref: (0, zod_mini.optional)((0, zod_mini.string)()),
117
+ epik: (0, zod_mini.optional)((0, zod_mini.string)()),
116
118
  utm_source: (0, zod_mini.optional)((0, zod_mini.string)()),
117
119
  utm_medium: (0, zod_mini.optional)((0, zod_mini.string)()),
118
120
  utm_campaign: (0, zod_mini.optional)((0, zod_mini.string)()),
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["pipe","string","transform","array","record","union","number","boolean","_null","object","optional","trim","minLength","maxLength","regex","uuid","_enum","iso","toLowerCase","email","e164","toUpperCase","url"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n webdriver: optional(boolean()),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n sccid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\n/**\n * How far an event's time may be from the server's before the client clock it was stamped with is\n * taken as wrong. A batch legitimately arrives late — a tab frozen in the background, a\n * session_start held back after a failed batch — by hours, not days; a phone set to another year\n * writes its sessions into that year.\n */\nconst MAX_CLOCK_SKEW = 24 * 60 * 60 * 1000;\n\n/**\n * Puts the events stamped by a wrong client clock onto the server's, where they are parsed. Only\n * the events outside `MAX_CLOCK_SKEW` move, so one bad event cannot drag the rest of its batch\n * along: they move together by their own latest one — the wrong clock at sending — keeping their\n * order and spacing, and one still out after that (a batch mixing two wrong clocks) is on no clock\n * at all and takes the server's time. Corrected rather than rejected, for the same reason values\n * are truncated: a wrong clock should cost the event its time, not the batch its events.\n */\nfunction alignClock<T extends { timestamp: string }>(events: T[], now = Date.now()): T[] {\n const within = (time: number) => Math.abs(now - time) <= MAX_CLOCK_SKEW;\n const times = events.map((event) => Date.parse(event.timestamp));\n const wrong = times.filter((time) => !within(time));\n if (wrong.length === 0) return events;\n const offset = now - Math.max(...wrong);\n return events.map((event, i) => {\n if (within(times[i])) return event;\n const shifted = times[i] + offset;\n return { ...event, timestamp: new Date(within(shifted) ? shifted : now).toISOString() };\n });\n}\n\nexport const createTrackEventSchema = pipe(\n array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n ).check(minLength(1), maxLength(100)),\n transform((events) => alignClock(events))\n);\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["pipe","string","transform","array","record","union","number","boolean","_null","object","optional","trim","minLength","maxLength","regex","uuid","_enum","iso","toLowerCase","email","e164","toUpperCase","url"],"sources":["../../src/schema/index.ts"],"sourcesContent":["import {\n enum as _enum,\n null as _null,\n array,\n boolean,\n e164,\n email,\n iso,\n maxLength,\n minLength,\n number,\n object,\n optional,\n pipe,\n record,\n regex,\n string,\n toLowerCase,\n toUpperCase,\n transform,\n trim,\n union,\n url,\n uuid,\n type z,\n} from 'zod/mini';\nimport type { Environment, Platform } from '../track/types';\n\nconst MAX_KEY_LENGTH = 128;\nconst MAX_VALUE_LENGTH = 512;\nconst MAX_PROPERTIES = 64;\n\n/**\n * Truncated rather than rejected. These schemas validate a whole batch at once, so refusing one\n * oversized value costs every event that traveled with it — and the values that overrun are the\n * ones derived from the page (a link's text, a URL carrying a long query), which no client can\n * bound in advance. A shortened value is worth more than a lost batch.\n */\nconst propertyText = pipe(\n string(),\n transform((value) => value.slice(0, MAX_VALUE_LENGTH))\n);\n\n/**\n * Keys are written by hand in instrumentation code, so an unusable one is a mistake in the host\n * rather than something the visitor typed. It is still dropped rather than rejected, for the same\n * reason: the mistake should cost that property, not the batch it happens to be in. Truncating a\n * key is not an option — two long keys would silently become one field.\n *\n * The key schema below is deliberately permissive so that this transform is reached at all; the\n * trimming it used to do happens here instead. `MAX_PROPERTIES` keeps the first N in insertion\n * order.\n */\nfunction takeProperties<T>(data: Record<string, T>): Record<string, T> {\n const result: Record<string, T> = {};\n let count = 0;\n for (const [rawKey, value] of Object.entries(data)) {\n if (count >= MAX_PROPERTIES) break;\n const key = rawKey.trim();\n if (!key || key.length > MAX_KEY_LENGTH) continue;\n result[key] = value;\n count++;\n }\n return result;\n}\n\n/**\n * Capped at GA4's own item-list limit, and truncated rather than rejected like every other\n * property limit here: an unbounded array is the one field a caller could still blow a batch\n * up with after the value and key limits.\n */\nconst MAX_ITEMS = 200;\n\nconst items = pipe(\n array(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n ),\n transform((list) => list.slice(0, MAX_ITEMS))\n);\n\nexport const ALL_PLATFORMS = [\n 'ios',\n 'android',\n 'web',\n 'macos',\n 'windows',\n 'linux',\n 'unknown',\n] as const satisfies Platform[];\n\nexport const ALL_ENVIRONMENTS = ['development', 'production'] as const satisfies Environment[];\n\nexport const tagsSchema = object({\n os: optional(string()),\n os_name: optional(string()),\n os_version: optional(string()),\n browser: optional(string()),\n browser_name: optional(string()),\n browser_version: optional(string()),\n device: optional(string()),\n device_id: optional(string().check(trim(), minLength(1), maxLength(36))),\n device_type: optional(string()),\n device_vendor: optional(string()),\n device_pixel_ratio: optional(number()),\n screen_width: optional(number()),\n screen_height: optional(number()),\n screen_resolution: optional(\n pipe(\n string().check(regex(/^\\d+x\\d+$/)),\n transform((v) => v as `${number}x${number}`)\n )\n ),\n webdriver: optional(boolean()),\n release: optional(string()),\n language: optional(string()),\n time_zone: optional(string()),\n page_location: optional(string()),\n page_referrer: optional(string()),\n page_title: optional(string()),\n page_load_id: optional(string()),\n /**\n * @deprecated Renamed to `page_location` in 7.0.0. Accepted so that events from clients\n * still on an older SDK are not stripped of their page URL at this boundary — a browser\n * bundle stays cached long after a backend deploys. Remove once those clients are gone;\n * `pageLocation` in `server/page-location.ts` is the only reader.\n */\n source_url: optional(string()),\n // app info\n advertising_id: optional(string()),\n install_referrer: optional(string()),\n // Meta Ads\n fbc: optional(string()),\n fbp: optional(string()),\n fbclid: optional(string()),\n ad_id: optional(string()),\n ad_name: optional(string()),\n adset_id: optional(string()),\n adset_name: optional(string()),\n campaign_id: optional(string()),\n campaign_name: optional(string()),\n placement: optional(string()),\n // Google Ads\n gclid: optional(string()),\n gclsrc: optional(string()),\n gad_source: optional(string()),\n gad_campaignid: optional(string()),\n // Reddit ads\n rdt_cid: optional(string()),\n rdt_uuid: optional(string()),\n // click ids\n dclid: optional(string()),\n ko_click_id: optional(string()),\n li_fat_id: optional(string()),\n msclkid: optional(string()),\n ScCid: optional(string()),\n ttclid: optional(string()),\n twclid: optional(string()),\n wbraid: optional(string()),\n gbraid: optional(string()),\n yclid: optional(string()),\n oppref: optional(string()),\n epik: optional(string()),\n // utm params\n utm_source: optional(string()),\n utm_medium: optional(string()),\n utm_campaign: optional(string()),\n utm_term: optional(string()),\n utm_content: optional(string()),\n utm_id: optional(string()),\n utm_source_platform: optional(string()),\n utm_creative_format: optional(string()),\n utm_marketing_tactic: optional(string()),\n});\n\nexport const propertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null(), items])),\n transform(takeProperties)\n )\n);\n\n/** Visitor properties differ from event properties only in taking no nested item lists. */\nconst visitorPropertiesSchema = optional(\n pipe(\n record(string(), union([propertyText, number(), boolean(), _null()])),\n transform(takeProperties)\n )\n);\n\n/**\n * How far an event's time may be from the server's before the client clock it was stamped with is\n * taken as wrong. A batch legitimately arrives late — a tab frozen in the background, a\n * session_start held back after a failed batch — by hours, not days; a phone set to another year\n * writes its sessions into that year.\n */\nconst MAX_CLOCK_SKEW = 24 * 60 * 60 * 1000;\n\n/**\n * Puts the events stamped by a wrong client clock onto the server's, where they are parsed. Only\n * the events outside `MAX_CLOCK_SKEW` move, so one bad event cannot drag the rest of its batch\n * along: they move together by their own latest one — the wrong clock at sending — keeping their\n * order and spacing, and one still out after that (a batch mixing two wrong clocks) is on no clock\n * at all and takes the server's time. Corrected rather than rejected, for the same reason values\n * are truncated: a wrong clock should cost the event its time, not the batch its events.\n */\nfunction alignClock<T extends { timestamp: string }>(events: T[], now = Date.now()): T[] {\n const within = (time: number) => Math.abs(now - time) <= MAX_CLOCK_SKEW;\n const times = events.map((event) => Date.parse(event.timestamp));\n const wrong = times.filter((time) => !within(time));\n if (wrong.length === 0) return events;\n const offset = now - Math.max(...wrong);\n return events.map((event, i) => {\n if (within(times[i])) return event;\n const shifted = times[i] + offset;\n return { ...event, timestamp: new Date(within(shifted) ? shifted : now).toISOString() };\n });\n}\n\nexport const createTrackEventSchema = pipe(\n array(\n object({\n name: string().check(trim(), minLength(1), maxLength(64)),\n visitor_id: uuid(),\n session_id: uuid(),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n timestamp: iso.datetime(),\n tags: tagsSchema,\n properties: propertiesSchema,\n })\n ).check(minLength(1), maxLength(100)),\n transform((events) => alignClock(events))\n);\n\nexport const createVisitorSchema = object({\n device_id: string().check(trim(), minLength(1), maxLength(36)),\n platform: _enum(ALL_PLATFORMS),\n environment: _enum(ALL_ENVIRONMENTS),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nconst emailValue = pipe(string().check(trim(), toLowerCase(), maxLength(320)), email());\n\n/** E.164: a plus sign (+) prefix, country code, then digits only, no dashes/parens/spaces. */\nconst phoneValue = pipe(string().check(trim()), e164());\n\nconst addressValue = object({\n first_name: optional(string().check(trim(), maxLength(128))),\n last_name: optional(string().check(trim(), maxLength(128))),\n street: optional(string().check(trim(), maxLength(256))),\n city: optional(string().check(trim(), maxLength(128))),\n /** User province, state, or region. Example: `Hampshire` */\n region: optional(string().check(trim(), maxLength(128))),\n postal_code: optional(string().check(trim(), maxLength(32))),\n /** 2-letter country code, per the ISO 3166-1 alpha-2 standard. Example: `UK` */\n country: optional(string().check(trim(), toUpperCase(), regex(/^[A-Z]{2}$/))),\n});\n\n/**\n * User-provided data (UPD) used for enhanced conversions, Customer Match, and demographics.\n * Values are sent unhashed; Google normalizes and hashes them before they reach its servers.\n *\n * Multiple values may be sent to increase the match rate: up to 3 emails, 3 phone numbers, and\n * 2 addresses.\n *\n * @see https://support.google.com/analytics/answer/14078702\n * @see https://support.google.com/google-ads/answer/13258081\n */\nexport const userProvidedDataSchema = object({\n email: optional(union([emailValue, array(emailValue).check(minLength(1), maxLength(3))])),\n phone_number: optional(union([phoneValue, array(phoneValue).check(minLength(1), maxLength(3))])),\n address: optional(union([addressValue, array(addressValue).check(minLength(1), maxLength(2))])),\n});\n\nexport const updateVisitorSchema = object({\n user_id: optional(uuid()),\n user_data: optional(userProvidedDataSchema),\n tags: tagsSchema,\n properties: visitorPropertiesSchema,\n});\n\nexport const createFeedbackSchema = object({\n name: string().check(minLength(1), maxLength(256)),\n email: email().check(maxLength(320)),\n message: string().check(minLength(1), maxLength(65536)),\n});\n\nconst noEmptyString = pipe(\n string().check(maxLength(256)),\n transform((v) => (v ? v : undefined))\n);\n\n/**\n * The schema for creating a link.\n * @see https://support.google.com/analytics/answer/10917952\n * */\nexport const createLinkSchema = object({\n /** The URL that the user is redirected to. */\n url: url().check(minLength(1), maxLength(1024)), // required\n\n /**\n * Campaign ID. Used to identify a specific campaign or promotion. This is a required key for GA4\n * data import. Use the same IDs that you use when uploading campaign cost data.\n */\n utm_id: optional(noEmptyString),\n\n /** Referrer, for example: google, newsletter4, billboard */\n utm_source: string().check(minLength(1), maxLength(256)), // required\n\n /** Marketing medium, for example: cpc, banner, email */\n utm_medium: string().check(minLength(1), maxLength(256)), // required\n\n /** Product, slogan, promo code, for example, spring_sale */\n utm_campaign: string().check(minLength(1), maxLength(256)), // required\n\n /** Paid keyword */\n utm_term: optional(noEmptyString),\n\n /**\n * Use to differentiate creatives. For example, if you have two call-to-action links within the\n * same email message, you can use utm_content and set different values for each so you can tell\n * which version is more effective.\n */\n utm_content: optional(noEmptyString),\n\n /**\n * The platform responsible for directing traffic to a given Analytics property (such as a buying\n * platform that sets budgets and targeting criteria or a platform that manages organic traffic\n * data). For example, Search Ads 360 or Display & Video 360.\n */\n utm_source_platform: optional(noEmptyString),\n\n /**\n * Type of creative, for example, display, native, video, search, utm_creative_format is not\n * currently reported in Google Analytics 4 properties.\n */\n utm_creative_format: optional(noEmptyString),\n\n /**\n * Targeting criteria applied to a campaign, for example, remarketing, prospecting,\n * utm_marketing_tactic is not currently reported in Google Analytics 4 properties.\n * */\n utm_marketing_tactic: optional(noEmptyString),\n});\n\nexport type CreateTrackEventDTO = z.output<typeof createTrackEventSchema>;\nexport type CreateFeedbackDTO = z.output<typeof createFeedbackSchema>;\nexport type CreateLinkDTO = z.output<typeof createLinkSchema>;\nexport type CreateVisitorDTO = z.output<typeof createVisitorSchema>;\nexport type UserProvidedDataDTO = z.output<typeof userProvidedDataSchema>;\nexport type UpdateVisitorDTO = z.output<typeof updateVisitorSchema>;\n"],"mappings":"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"}