Published on 2025-07-28T05:38:35.945Z

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.

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/<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
    /**
     * 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 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: r.hostname,
                    rp: r.pathname
                  },
                  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),
              });
            }
          } catch (error) {
            console.error('Error tracking AI bot:', error);
          }
        }
    
        return response;
      },
    };