Saltar para o conteúdo

Monitorização de crawlers de IA

Atualizado em 18 de outubro de 2026

Os crawlers de IA não executam JavaScript, pelo que o script do Statsdot nunca os deteta. Para saber quais deles leem o seu site, o seu servidor reporta os pedidos ao Statsdot. Poderá então ver, no relatório do site, cada crawler com o seu número de pedidos e as páginas que os crawlers mais leem.

Apenas são armazenados os pedidos cujo user agent corresponde a um crawler do diretório de crawlers de IA, juntamente com o crawler, o caminho sem query string e o código de estado. Os pedidos de pessoas são ignorados, mesmo que o seu servidor os envie, e não é armazenado qualquer endereço IP.

1. Ativar a funcionalidade

Nas definições do site, em AI crawler tracking, escolha Turn on and create a key. Copie a chave (começa por sdb_). A chave apenas pode reportar pedidos de crawlers; renove-a no mesmo local caso seja comprometida.

2. Ligar o seu site

WordPress

Em Settings > Statsdot do plugin, cole a chave em AI crawler tracking e guarde. É tudo.

Laravel

Adicione este middleware ao grupo web. O reporte é feito após o envio da resposta, pelo que os crawlers não sofrem atrasos:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Symfony\Component\HttpFoundation\Response;

class ReportAiCrawlers
{
    private const TOKENS = ['gptbot', 'oai-searchbot', 'chatgpt-user', 'claudebot', 'claude-user', 'claude-searchbot', 'perplexitybot', 'perplexity-user', 'google-extended', 'googlebot', 'bingbot', 'applebot', 'meta-externalagent', 'bytespider', 'ccbot', 'amazonbot', 'duckassistbot', 'mistralai-user'];

    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);
    }

    public function terminate(Request $request, Response $response): void
    {
        $agent = strtolower((string) $request->userAgent());

        foreach (self::TOKENS as $token) {
            if (str_contains($agent, $token)) {
                Http::timeout(2)->withHeaders(['X-Statsdot-Bot-Key' => config('services.statsdot.bot_key')])
                    ->post('https://statsdot.com/api/bots', [
                        'user_agent' => $request->userAgent(),
                        'url' => $request->fullUrl(),
                        'status' => $response->getStatusCode(),
                    ]);

                return;
            }
        }
    }
}

Coloque a chave no .env como STATSDOT_BOT_KEY e em config/services.php como 'statsdot' => ['bot_key' => env('STATSDOT_BOT_KEY')]. O Statsdot reconhece mais crawlers do que a lista curta acima; estenda-a com os tokens do diretório que lhe interessam.

PHP simples

No final do seu front controller (por exemplo, index.php), após a página ter sido enviada:

$agent = $_SERVER['HTTP_USER_AGENT'] ?? '';

if (preg_match('/gptbot|oai-searchbot|chatgpt-user|claudebot|claude-user|claude-searchbot|perplexitybot|perplexity-user|googlebot|bingbot|applebot|meta-externalagent|bytespider|ccbot|amazonbot/i', $agent)) {
    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request();
    }

    $context = stream_context_create(['http' => [
        'method' => 'POST',
        'timeout' => 2,
        'header' => "Content-Type: application/json\r\nX-Statsdot-Bot-Key: sdb_your_key\r\n",
        'content' => json_encode([
            'user_agent' => $agent,
            'url' => 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
            'status' => http_response_code(),
        ]),
    ]]);

    @file_get_contents('https://statsdot.com/api/bots', false, $context);
}

Node.js e Express

const CRAWLERS = /gptbot|oai-searchbot|chatgpt-user|claudebot|claude-user|claude-searchbot|perplexitybot|perplexity-user|googlebot|bingbot|applebot|meta-externalagent|bytespider|ccbot|amazonbot/i;

app.use((req, res, next) => {
  const agent = req.get('user-agent') || '';
  if (CRAWLERS.test(agent)) {
    res.on('finish', () => {
      fetch('https://statsdot.com/api/bots', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Statsdot-Bot-Key': process.env.STATSDOT_BOT_KEY },
        body: JSON.stringify({ user_agent: agent, url: `${req.protocol}://${req.get('host')}${req.originalUrl}`, status: res.statusCode }),
      }).catch(() => {});
    });
  }
  next();
});

Next.js

No middleware.ts, reporte sem atrasar a resposta:

import { NextResponse, type NextRequest, type NextFetchEvent } from 'next/server';

const CRAWLERS = /gptbot|oai-searchbot|chatgpt-user|claudebot|claude-user|claude-searchbot|perplexitybot|perplexity-user|googlebot|bingbot|applebot|meta-externalagent|bytespider|ccbot|amazonbot/i;

export function middleware(request: NextRequest, event: NextFetchEvent) {
  const agent = request.headers.get('user-agent') ?? '';
  if (CRAWLERS.test(agent)) {
    event.waitUntil(fetch('https://statsdot.com/api/bots', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-Statsdot-Bot-Key': process.env.STATSDOT_BOT_KEY! },
      body: JSON.stringify({ user_agent: agent, url: request.url }),
    }).catch(() => {}));
  }
  return NextResponse.next();
}

O endpoint

POST https://statsdot.com/api/bots com o cabeçalho X-Statsdot-Bot-Key e um corpo JSON {"user_agent": "...", "url": "...", "status": 200}, ou {"events": [...]} com até 100 pedidos. Responde com 202 e o número registado. Até 600 pedidos por minuto por chave.

Limites

Cada conta regista até 100.000 pedidos de crawlers por mês em todos os seus sites; para além disso, não são registados até ao mês seguinte. Os pedidos de crawlers não contam para os eventos do seu plano. São mantidos durante o mesmo período que as suas visitas (24 meses).