/** * Whether a request announces itself as software rather than a person. * * The voice measurement divides durable use by impressions, and crawlers are * impressions that can never convert — every one that slips in drags each * weight toward zero. The dwell-or-scroll beat already filters most of them, * but Google's renderer runs timers, so a declared bot can pass a four-second * dwell without a person existing. * * Declared is the operative word. This reads the User-Agent string, which * catches every honest crawler — search engines, link unfurlers, validators — * and none of the dishonest ones. That is the right trade here: a liar gets * counted as a visitor who never signed up, which is noise the model already * survives; there is nothing worth defending beyond that, since the only * thing at stake is the quality of our own statistics. */ const BOT_UA = /bot|crawler|spider|crawling|slurp|bingpreview|headless|lighthouse|facebookexternalhit|whatsapp|telegram|skypeuripreview|discordbot|embedly|pinterest|linkedinbot|vkshare|validator|fetcher|monitor|scrape/i; export function isDeclaredBot(userAgent: string | undefined): boolean { return userAgent !== undefined && BOT_UA.test(userAgent); }