AI crawler tracking
See which pages ChatGPT, Claude, Perplexity, and other AI crawlers read, with a short snippet on your server.
AI tools such as ChatGPT, Claude, and Perplexity send crawlers to read your pages. These crawlers do not run JavaScript, so the tracking script never sees them. To count them, your own server tells Dodolytics about each visit of an AI crawler.
What you get
The Bots report gets a card, AI crawlers on your server:
- Why they came: the hits of three groups of crawlers.
- AI assistants: a person asked an AI tool, for example ChatGPT, and it read your page for them (ChatGPT-User, Claude-User, Perplexity-User).
- AI search: indexing for an AI search engine (OAI-SearchBot, Claude-SearchBot, PerplexityBot).
- AI training: collecting text to train AI models (GPTBot, ClaudeBot, CCBot).
- Each crawler, with its Purpose, its Hits (requests), the number of different Pages it read, and when it was Last seen.
- Pages they read: the 20 pages with the most hits, with the hits of each group. Use the search box above the table to find other pages.
*matches any characters:/blog/*finds every page under/blog/. A search with no*finds pages that contain the text.
These hits are not counted in any other report. They are not visitors, so the Dashboard and Pages do not change. The report filters do not apply to this card, and Real-time does not show it.
Before you start
You need your tracking ID. Open the website, click Settings, and copy the Tracking ID. Until your server sends the first hit, the card shows Not set up yet with your tracking ID.
Use one of the three ways below. Each one sends only the requests of AI crawlers. Requests of people are not sent.
Way 1: PHP
Put this code in a file that every page loads, for example
wp-config.php or your index.php, on the
line after the first <?php. Change
YOUR_TRACKING_ID.
// Dodolytics: count AI crawlers.
(function () {
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (!preg_match('/GPTBot|ChatGPT-User|OAI-SearchBot|ClaudeBot|Claude-User|Claude-SearchBot|anthropic-ai|PerplexityBot|Perplexity-User|Google-CloudVertexBot|GoogleOther|meta-externalagent|meta-externalfetcher|Amazonbot|MistralAI-User|DuckAssistBot|cohere-ai|YouBot|Diffbot|CCBot|Bytespider/i', $ua)) {
return;
}
$ch = curl_init('https://dodolytics.com/collect-bot');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'website_id' => 'YOUR_TRACKING_ID',
'user_agent' => $ua,
'path' => $_SERVER['REQUEST_URI'] ?? '/',
'hostname' => $_SERVER['HTTP_HOST'] ?? '',
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT_MS => 1000,
]);
curl_exec($ch);
})();
Only a request of an AI crawler waits for this call, at most one second. Pages for people do not wait.
Way 2: nginx
nginx can copy each crawler request to Dodolytics with
mirror, with no change to your website's code. Add this
block inside your server { } block. Change
YOUR_TRACKING_ID.
location = /_dodolytics_ai {
internal;
if ($http_user_agent !~* "GPTBot|ChatGPT-User|OAI-SearchBot|ClaudeBot|Claude-User|Claude-SearchBot|anthropic-ai|PerplexityBot|Perplexity-User|Google-CloudVertexBot|GoogleOther|meta-externalagent|meta-externalfetcher|Amazonbot|MistralAI-User|DuckAssistBot|cohere-ai|YouBot|Diffbot|CCBot|Bytespider") {
return 204;
}
proxy_pass https://dodolytics.com/collect-bot?website_id=YOUR_TRACKING_ID;
proxy_method POST;
proxy_pass_request_headers off;
proxy_pass_request_body off;
proxy_set_header Host dodolytics.com;
proxy_set_header X-Dodolytics-User-Agent $http_user_agent;
proxy_set_header X-Dodolytics-Path $request_uri;
proxy_set_header X-Dodolytics-Host $host;
proxy_ssl_server_name on;
proxy_connect_timeout 2s;
proxy_read_timeout 2s;
}
Then add these two lines to one location block: the block that sends your pages.
mirror /_dodolytics_ai;
mirror_request_body off;
- PHP website (for example WordPress): the
location ~ \.php$block. Notlocation /: there,try_filessends the request on toindex.phpbefore the copy is made, and most pages are not counted. - An app behind
proxy_pass(for example Node.js or Python): the block with theproxy_passto your app. - Static files:
location /, withtry_files $uri $uri/index.html =404;. With$uri/instead, nginx counts a folder address such as/blog/two times.
Run sudo nginx -t to check the configuration, then
sudo systemctl reload nginx. The copy does not send
cookies or other headers of the request.
Way 3: any other language
When the User-Agent of a request names an AI crawler, send one
POST request with a JSON body:
curl -X POST https://dodolytics.com/collect-bot \
-H 'Content-Type: application/json' \
-d '{"website_id":"YOUR_TRACKING_ID","user_agent":"GPTBot/1.2","path":"/blog/post","hostname":"example.com"}'
website_id: your tracking ID.user_agent: the User-Agent of the crawler's request.path: the address that the crawler asked for. A full URL is also accepted.hostname(optional): the host of your website. Use it if allowed hostnames are on.
The answer is always 204, also when Dodolytics does not
keep the hit. Your server does not need to read it.
What Dodolytics keeps
- The name of the crawler, the path without the query string, and the time. Not the IP address.
- Only hits of the AI crawlers on the list below. Dodolytics ignores every other request, also of other bots.
- Hits count only from the time that you add the code. Older visits of crawlers are not known.
- Up to 100,000 hits for each website in a calendar month. More hits that month are not stored. The card shows how many hits are stored this month.
The AI crawlers on the list
GPTBot, ChatGPT-User, OAI-SearchBot, ClaudeBot, Claude-User, Claude-SearchBot, anthropic-ai, PerplexityBot, Perplexity-User, Google-CloudVertexBot, GoogleOther, Meta-ExternalAgent, Meta-ExternalFetcher, Amazonbot, MistralAI-User, DuckAssistBot, cohere-ai, YouBot, Diffbot, CCBot, Bytespider.
Your tracking ID is public, the same as in the tracking script. A person who knows it can send false hits. A crawler that uses the name of a normal browser is not counted.
Related articles
Still need help? Ask on our feedback board or see all topics.