AI CRAWLERS
AI crawler tracking
See which AI and search crawlers read your site, verified against the operators own IP ranges.
Normal analytics cannot see crawlers, because they do not run JavaScript. To see them, a small Cloudflare Worker in front of your site forwards each crawler visit to your dashboard. Visitors are untouched: the Worker only reports requests whose user agent looks like a known crawler.
| What you get | Detail |
|---|---|
| Per crawler visits | 28 tracked crawlers from OpenAI, Anthropic, Google, Perplexity, Meta, Apple and more. |
| Verification | Each visit is checked against the IP ranges the operator publishes, so spoofed user agents are marked. |
| Pages and status | Which paths are read and what status they returned, including 404s. |
Set up
- Open Crawlers in your website and copy your API key from Settings.
- Create a Worker in Cloudflare and paste the snippet below.
- Add a secret named
ANALYTICS_KEYwith your API key. - Route the Worker to your domain, for example
example.com/*.
// Cloudflare Worker: forwards AI and search crawler visits to Analytics by 5H3LL.
// 1. Add a Worker secret named ANALYTICS_KEY containing your website's API key.
// 2. Route this Worker to your domain, for example example.com/*.
const CRAWLER_TOKENS = [
'ChatGPT-User', 'Claude-User', 'Perplexity-User', 'Google-Agent',
'Google-GeminiNotebook', 'Amzn-User', 'meta-externalfetcher', 'DuckAssistBot',
'MistralAI-User', 'OAI-SearchBot', 'Claude-SearchBot', 'PerplexityBot',
'Googlebot', 'Google-InspectionTool', 'Storebot-Google', 'bingbot',
'Amzn-SearchBot', 'Applebot', 'DuckDuckBot', 'meta-webindexer',
'GPTBot', 'ClaudeBot', 'Amazonbot', 'meta-externalagent',
'CCBot', 'OAI-AdsBot', 'facebookexternalhit', 'GoogleOther',
];
const CRAWLERS = new RegExp(CRAWLER_TOKENS.join('|'), 'i');
export default {
async fetch(request, env, ctx) {
const response = await fetch(request);
const userAgent = request.headers.get('user-agent') || '';
if (CRAWLERS.test(userAgent)) {
ctx.waitUntil(
fetch('https://analytics.5h3ll.site/api/v1/crawls', {
method: 'POST',
headers: { authorization: 'Bearer ' + env.ANALYTICS_KEY, 'content-type': 'application/json' },
body: JSON.stringify({ hits: [{ user_agent: userAgent, ip: request.headers.get('cf-connecting-ip'), url: request.url, status: response.status }] }),
}).catch(() => {}),
);
}
return response;
},
};npx wrangler secret put ANALYTICS_KEYThe snippet is generated from the same list as the crawler directory, so it always matches what we can classify.
Verification states
| State | Meaning |
|---|---|
verified | The user agent matched and the request came from an IP range the operator publishes. |
claimed | The user agent matched, but the IP is outside the published ranges. Treat as possibly spoofed. |
unverifiable | The operator publishes no IP ranges, so only the user agent can be checked. |
Allowance
Crawler visits have their own monthly allowance on every plan, separate from page views. They never use your page view quota.
| Plan | Crawler visits per month |
|---|---|
| Free | 2,000 |
| Starter | 10,000 |
| Indie | 50,000 |
| Growth | 250,000 |
| Founder Lifetime | 250,000 |
Privacy
Crawler IP addresses are used to verify a visit and are not stored. Only daily counts per crawler, path and status are kept, for 400 days.
Something missing or wrong? Open a support ticket.