@chadanalytics/bot
v0.3.0
Published
Track AI crawler visits (GPTBot, ClaudeBot, PerplexityBot…) for Chad Analytics
Maintainers
Readme
@chadanalytics/bot
Track AI crawler visits — the traffic your JS snippet can't see.
ChatGPT, Claude, Perplexity, and friends fetch your pages with plain HTTP requests. They never run JavaScript, so a client-side analytics snippet is blind to them. This package detects known AI bot user-agents server-side and reports each visit to Chad Analytics — zero dependencies, near-zero overhead.
Three categories:
- aiAnswers — ChatGPT-User, Claude-User, Perplexity-User — a bot fetching your page live to answer someone's question right now.
- indexing — OAI-SearchBot, Googlebot, Bingbot, PerplexityBot, DuckDuckBot — classic search crawlers building a search index.
- training — GPTBot, ClaudeBot, CCBot, Google-Extended — bots scraping your content to train a model.
Install
npm install @chadanalytics/botUsage
Choose the adapter that owns your server request path. The browser snippet still tracks human and referral traffic; this package adds the server-side crawler requests that browsers never see.
| Runtime | Import |
| --- | --- |
| Node HTTP | @chadanalytics/bot |
| Express / connect | @chadanalytics/bot/express |
| Next.js | @chadanalytics/bot/next |
| Fastify | @chadanalytics/bot/fastify |
| Hono | @chadanalytics/bot/hono |
| Astro | @chadanalytics/bot/astro |
| Nuxt / Nitro | @chadanalytics/bot/nuxt |
| SvelteKit | @chadanalytics/bot/sveltekit |
| Cloudflare Workers | @chadanalytics/bot/cloudflare |
| Bun | @chadanalytics/bot/bun |
| Deno | npm:@chadanalytics/bot/deno |
Express / connect
const { chadBot } = require("@chadanalytics/bot");
app.use(chadBot({ site: "CH-XXXX" }));Next.js middleware
// middleware.ts
import { chadBotTracking } from "@chadanalytics/bot/next";
export const middleware = chadBotTracking({ site: "CH-XXXX" });Cloudflare Worker
import { withChadBotTracking } from "@chadanalytics/bot/cloudflare";
export default withChadBotTracking({ site: "CH-XXXX" }, {
async fetch(request) { return handleRequest(request); },
});Webflow behind Cloudflare
Webflow does not expose request middleware, so attach a Worker route to the custom domain that Cloudflare already proxies. The helper continues to the existing Webflow origin and returns its exact response:
import { createWebflowCloudflareWorker } from "@chadanalytics/bot/cloudflare";
export default createWebflowCloudflareWorker();Set CHAD_SITE_ID as a Worker variable and route the Worker over the hostname
that serves Webflow. The ready-to-deploy template, generator, privacy notes and
verification command live in packages/chad-webflow-cloudflare in the Chad
Analytics distribution.
Fastify
const Fastify = require("fastify");
const { chadBotTracking } = require("@chadanalytics/bot/fastify");
const app = Fastify();
await app.register(chadBotTracking({ site: "CH-XXXX" }));Hono
import { Hono } from "hono";
import { chadBotTracking } from "@chadanalytics/bot/hono";
const app = new Hono();
app.use("*", chadBotTracking({ site: "CH-XXXX" }));Astro
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";
import { chadBotTracking } from "@chadanalytics/bot/astro";
export const onRequest = defineMiddleware(
chadBotTracking({ site: "CH-XXXX" })
);Astro must use a server or hybrid output for middleware to observe crawler requests. A completely static export has no request-time server; put the adapter at the CDN, reverse proxy, or origin that serves it instead.
Nuxt / Nitro
// server/middleware/chad-bot.ts
import { chadBotTracking } from "@chadanalytics/bot/nuxt";
export default defineEventHandler(
chadBotTracking({ site: "CH-XXXX" })
);SvelteKit
// src/hooks.server.ts
import { chadBotTracking } from "@chadanalytics/bot/sveltekit";
export const handle = chadBotTracking({ site: "CH-XXXX" });If you already have a SvelteKit handle, compose the hooks with
sequence(existingHandle, chadBotTracking(...)) from @sveltejs/kit/hooks.
Bun
import { withChadBotTracking } from "@chadanalytics/bot/bun";
Bun.serve({
fetch: withChadBotTracking({ site: "CH-XXXX" }, async () => {
return new Response("ok");
}),
});Deno
import { withChadBotTracking } from "npm:@chadanalytics/bot/deno";
Deno.serve(withChadBotTracking({ site: "CH-XXXX" }, async () => {
return new Response("ok");
}));Plain node http
const http = require("http");
const { trackBotVisit } = require("@chadanalytics/bot");
http
.createServer((req, res) => {
trackBotVisit(req, { site: "CH-XXXX" });
res.end("ok");
})
.listen(3000);Fire-and-forget, always
trackBotVisit never awaits its network call and never throws — if
detectBot(req.headers["user-agent"]) finds nothing, it returns immediately;
if the report fails to send, it's swallowed. Your request handler's latency
is unaffected either way. Never await it.
API
detectBot(userAgent) → { name, provider, category } | nulltrackBotVisit(req, { site, apiUrl }) → voidchadBot({ site, apiUrl }) → (req, res, next) => voidchadBotTracking({ site, apiUrl })from/nextand/expresswithChadBotTracking(options, handler)from/cloudflarecreateWebflowCloudflareWorker(options?)from/cloudflare; readsCHAD_SITE_IDfrom the Worker environment and forwards to the existing originchadBotTracking(options)from/fastify,/hono,/astro,/nuxt, and/sveltekitwithChadBotTracking(options, handler)from/bunand/deno
apiUrl defaults to https://chadanalytics.com; override it for self-hosted
or staging setups.
What this can and cannot prove
Crawler names come from the request's user-agent and Chad reclassifies that value at ingestion. This is the same signal exposed by ordinary web-server logs, not cryptographic identity: any client can spoof a bot user-agent. Treat the numbers as crawler activity signals, not as security or billing evidence.
This package is application middleware. It does not install itself in Shopify,
WordPress, Webflow, or another hosted builder, and it does not represent a
marketplace listing. Those surfaces require their own app/plugin approval and
provider credentials. For a static site, install this at the CDN/server layer
that receives requests, while keeping the Chad browser snippet in the site
<head> for human visits and AI referral attribution.
