# AI, LLM, agent, bot analytics using Cloudflare Workers Gain clear insights into how AI and other bots interact with your website using PlainSignal's integration with Cloudflare Workers. Deploying through Workers enables efficient, edge-based tracking of bot activity, providing you with a comprehensive understanding of their engagement with your content. This solution is designed for any website hosted on Cloudflare and requires minimal configuration. Our edge-based approach ensures fast performance and comprehensive tracking across all your web pages, giving you the data you need to optimize your site for both human and AI visitors. Breadcrumb navigation - [Privacy-first, simple website analytics](https://plainsignal.com/) - [Analytics integrations](https://plainsignal.com/integrations) - [Cloudflare](https://plainsignal.com/integrations/cloudflare) ## Features * Completely backend solution (no scripts) * Deploy the worker code below with Cloudflare Workers * Zero impact on site performance * Global distribution * Works with any website on Cloudflare * No code changes to your actual website * Identifies all major AI bots and crawlers * Hourly breakdown analytics reports by page path, agent and operators ## Cloudflare <> PlainSignal analytics integration Step by Step Guide To Track AI, LLM, Agent, Bot Traffics using Cloudflare Workers ### Step#1: Get your DomainID and DomainApiKey from PlainSignal If you already added your website to PlainSignal for tracking, then follow the sub-steps below (Learn how to create your first website analytics in PlainSignal if you haven't done before): * Go to `https://app.plainsignal.com/s/<your domain>/settings` * In the `Configuration` panel you will see your `DomainID` * In the same `Configuration` panel, to get your `DomainApiKey` visible click on the `*****` link At the end of this step you should have 3 values: * DomainName * DomainID * DomainApiKey ### Step#2: Create Cloudflare worker In the following script replace the following placeholders: * {YourDomainName} with your `DomainName` from the step above * {YourDomainID} with your `DomainID` from the step above * {YourDomainApiKey} with your `DomainApiKey` from the step above ```js /** * Welcome to Cloudflare Workers! This is your first worker. * * - Run "npm run dev" in your terminal to start a development server * - Open a browser tab at http://localhost:8787/ to see your worker in action * - Run "npm run deploy" to publish your worker * * Learn more at https://developers.cloudflare.com/workers/ */ const plainSignalBotPatterns = /(GPTBot|ChatGPT-User|OAI-SearchBot|Amazonbot|Applebot-Extended|Applebot|archive\.org_bot|adidxbot|MicrosoftPreview|bingbot|Bytespider|ClaudeBot|Claude-User|Claude-SearchBot|DuckAssistBot|DuckDuckBot|Googlebot-Image|Googlebot-Video|Googlebot-News|Googlebot|Storebot-Google|Google-InspectionTool|GoogleOther-Image|GoogleOther-Video|GoogleOther|GoogleCloud-VertexBot|Google-Extended|APIs-Google|AdsBot-Google-Mobile|AdsBot-Google|Mediapartners-Google|Google-Safety|FeedFetcher-Google|GoogleProducer|Google-Read-Aloud|Google-Site-Verification|facebookexternalhit|facebookcatalog|meta-externalagent|meta-externalfetcher|MistralAI-User|PerplexityBot|Perplexity-User|PetalBot|ProRateInc|Timpibot|YandexBot|CCBot|LinkedInBot|Yahoo!\sSlurp)/i const plainSignalCfgMappings = { '{YourDomainName}': { domainID: '{YourDomainID}', domainApiKey: '{YourDomainApiKey}' } } // Cloudflare Worker script to track AI bots export default { async fetch(request, env, ctx) { const response = await fetch(request); const { url, headers, cf } = request; const userAgent = headers.get('user-agent') || ''; if (plainSignalBotPatterns.test(userAgent)) { try { const r = new URL(url) const cfg = plainSignalCfgMappings[r.hostname] if (cfg !== null || cfg !== undefined) { const referrer = headers.get('referer') // NOTE: It is not a typo! let rd = '' let rp = '' if (referrer !== null && referrer !== undefined && referrer !== '') { const ref = new URL(referrer) rd = ref.hostname rp = ref.pathname } const p = r.searchParams const payload = { b: { d: { a: userAgent, z: cf?.timezone, }, l: { c: cf?.country }, s: { us: p.get('utm_source') || p.get('source'), um: p.get('utm_medium'), uc: p.get('utm_campaign'), ut: p.get('utm_term'), uo: p.get('utm_content'), ur: p.get('ref'), rd: rd, rp: rp }, p: { p: r.pathname, }, ci: (headers.get('cf-connecting-ip') || '') + userAgent + (headers.get('sec-ch-ua') || '') } } await fetch('https://eu.plainsignal.com/s/' + cfg.domainID + '/19', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': cfg.domainApiKey, }, body: JSON.stringify(payload), }); } else { console.log('Config not found for hostname:', r.hostname); } } catch (error) { console.error('Error tracking AI bot:', error); } } return response; }, }; ``` #### Multiple Sites with Single Worker Script If you have multiple sites or subdomains hosted in Cloudflare and want to leverage analytics with single Cloudflare Worker you will need to modify the first part of the script. But first of all collect `DomainID`, `DomainApiKey`, `DomainName` information from PlainSignal settings page as in the first step for each domain/subdomain. Then add each site configuration like below: ``` const plainSignalCfgMappings = { '{YourDomainName1}': { domainID: '{YourDomainID1}', domainApiKey: '{YourDomainApiKey1}' }, '{YourDomainName2}': { domainID: '{YourDomainID2}', domainApiKey: '{YourDomainApiKey2}' } } ``` In the example above, single Worker configured to submit bot analytics data in one configuration for 2 domains. Add more domains to the configuration, there is no limit. Just ensure each site has different `DomainID`, `DomainName` and `DomainApiKey` values. ## Other integrations - [Next.js <> PlainSignal analytics integration guidelines](https://plainsignal.com/integrations/nextjs) ## Canonical Human friendly, reader version of this article is available at [Cloudflare](https://plainsignal.com/integrations/cloudflare) ## Copyright (c) 2025 [PlainSignal](https://plainsignal.com/ "Privacy-focused, simple website analytics")