New Kitbase MCP is live — talk to your analytics in plain English
Back to Blog
AI Crawlers Bot Detection Tutorial

How to Detect AI Bots on WordPress (Without a Bloated Plugin)

Detect GPTBot, ClaudeBot, and other AI crawlers on WordPress with a tiny must-use plugin (No bloated marketplace plugin, no admin screen, no page-load hit).

K
Kitbase Team
·

To detect AI bots on WordPress, drop a small must-use plugin into wp-content/mu-plugins/ that forwards each front-end request’s signals to a server-side detection endpoint without marketplace plugin, no admin screen, and no hit to your page load. WordPress sites are among the most heavily crawled on the web, and the crawlers doing it (GPTBot, ClaudeBot, PerplexityBot, Googlebot) never run JavaScript, so your analytics plugin sees none of them. This guide sets up detection the lightweight way, mirroring the official WordPress crawler-detection guide, in about the time it takes to edit two files.

Why WordPress sites get crawled so heavily by AI bots.

WordPress powers a huge share of the web’s content, and AI crawlers are content-hungry by design. A typical WordPress site is exactly what they want: lots of text-dense, publicly readable pages (posts, category archives, tag pages, pagination) on stable URLs. That structure multiplies the surface area a crawler will fetch. A single blog can expose the same post through its permalink, a category archive, a tag archive, and paginated index pages, and crawlers happily walk all of them.

The result is that AI bots often account for a meaningful and growing slice of a WordPress site’s raw traffic and you have no visibility into it from inside WordPress. Your analytics plugin, whatever it is, records a visit only when a browser runs its tracking script. AI crawlers like GPTBot fetch your rendered HTML and stop; they never execute the script, so tag-based analytics reports zero crawler traffic. The pages those bots read are the pages generative models learn about you from, and you’re currently flying blind on all of it.

Why a must-use plugin beats a marketplace plugin.

The instinct on WordPress is to reach for a plugin from the directory. For bot detection specifically, a must-use plugin (mu-plugin) is the better tool, and it’s smaller than the alternative in every way that matters.

Must-use plugin (this guide)Typical marketplace bot plugin
Code footprintOne short file you can read in fullThousands of lines, admin UI, assets
Runs on every requestYes — loads before regular pluginsDepends; often only when active
Can be deactivated by accidentNo — not toggleable from adminYes — one click disables coverage
Survives theme/plugin changesYes — theme-independentSometimes tied to theme or settings
Dashboard bloatNone — no admin screenAdds menus, notices, upsells
What it doesForwards signals; classification is server-sideOften does detection in-process, adding load

A must-use plugin runs on every request, loads before regular plugins, and can’t be deactivated from the admin so your bot coverage survives theme switches and plugin housekeeping. You could paste the same snippet into your theme’s functions.php, but that ties it to the active theme and it vanishes the moment you switch themes. The mu-plugin is theme-independent and the recommended approach.

Prerequisites.

Add a constant to wp-config.php, above the /* That's all, stop editing! */ line:

define( 'KITBASE_API_KEY', 'sk_kitbase_…' ); // your project's SECRET key, not the browser SDK key

Use your project’s secret key (sk_kitbase_…) from Kitbase, not the browser SDK key. It stays server-side in wp-config.php and is never exposed to visitors.

The must-use plugin

Create wp-content/mu-plugins/kitbase-crawler.php (make the mu-plugins folder if it doesn’t exist). The request is sent non-blocking, so it never adds latency to your page load:

<?php
/**
 * Plugin Name: Kitbase Crawler Detection
 * Description: Forwards front-end request signals to Kitbase for server-side bot & crawler detection.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

add_action( 'template_redirect', function () {
	// Only forward real front-end page requests.
	if ( is_admin() || wp_doing_cron() || wp_doing_ajax() ) {
		return;
	}

	$server = $_SERVER;

	// Behind a proxy/CDN, the visitor IP is the first entry of X-Forwarded-For.
	$ip = $server['REMOTE_ADDR'] ?? null;
	if ( ! empty( $server['HTTP_X_FORWARDED_FOR'] ) ) {
		$ip = trim( explode( ',', $server['HTTP_X_FORWARDED_FOR'] )[0] );
	}

	$body = array(
		'events' => array(
			array(
				'user_agent'      => $server['HTTP_USER_AGENT'] ?? null,
				'ip_address'      => $ip,
				'method'          => $server['REQUEST_METHOD'] ?? null,
				'host'            => $server['HTTP_HOST'] ?? null,
				'path'            => wp_parse_url( $server['REQUEST_URI'] ?? '', PHP_URL_PATH ),
				'referrer'        => $server['HTTP_REFERER'] ?? null,
				'signature'       => $server['HTTP_SIGNATURE'] ?? null,
				'signature_input' => $server['HTTP_SIGNATURE_INPUT'] ?? null,
				'signature_agent' => $server['HTTP_SIGNATURE_AGENT'] ?? null,
			),
		),
	);

	// Fire-and-forget: blocking => false never delays the response.
	wp_remote_post( 'https://ingest.kitbase.dev/ingest/v1/server', array(
		'blocking'  => false,
		'timeout'   => 1,
		'headers'   => array(
			'Authorization' => 'Bearer ' . KITBASE_API_KEY,
			'Content-Type'  => 'application/json',
		),
		'body'      => wp_json_encode( $body ),
	) );
} );

That’s it no build step, no admin screen. The next crawler to hit your site shows up in Kitbase.

What it does, line by line.

  • template_redirect fires on real front-end page loads, so the snippet only runs where it should.
  • The is_admin() / wp_doing_cron() / wp_doing_ajax() guard skips admin pages, cron jobs, and AJAX calls, you’re forwarding page views not background machinery.
  • The X-Forwarded-For handling grabs the true visitor IP when you’re behind a CDN or reverse proxy, falling back to REMOTE_ADDR otherwise.
  • 'blocking' => false makes wp_remote_post fire-and-forget. WordPress dispatches the request and moves on without waiting for a response, so the page render is never delayed.
  • The signature* headers carry Web Bot Auth signatures. Forwarding them lets Kitbase cryptographically verify a crawler’s claimed identity when it signs its requests which stronger than an IP-range check alone.

Because classification happens on Kitbase’s side, this plugin does no detection work in-process. It reads a few request values and fires one non-blocking HTTP call. That’s the whole reason it can run on every request without weighing your site down unlike bot plugins that do pattern-matching, rule evaluation, and logging inside your PHP process on every page view.

Privacy: only bots are stored.

Forwarding every request doesn’t mean storing every visitor. Human visitors’ signals are used only to classify the request in memory and are then discarded. Only bot and crawler requests are persisted. For those, the raw IP is stored only when IP logging is enabled for the project; otherwise it’s used to derive geolocation (country, region, city) and then dropped. It’s safe to run on every front-end request precisely because humans never land in the dataset.

High-traffic sites.

wp_remote_post opens one non-blocking HTTP request per page view. On a busy site that’s a lot of outbound calls. If that becomes a concern, buffer the signals to an object cache or a log, and ship them in batches of up to 500 on a short interval instead of one call per request. The nginx guide documents the same log-and-ship batching pattern if you’d rather move detection out of PHP entirely.

What the dashboard shows.

Once the plugin is live, WordPress crawler traffic becomes a dataset you can actually read in Kitbase:

  • Which AI bots visit: GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot, Googlebot, and more, each identified by name rather than lumped into “bots.”
  • Which pages each bot crawls most: the per-path view that reveals which pages AI bots read most on your site, so you can tell whether your best posts are being reached or skipped.
  • Verified vs. spoofed: every hit labelled real or impostor using published IP ranges and Web Bot Auth signatures, so a scraper faking a GPTBot user agent doesn’t inflate your numbers.
  • Trends and geography: whether crawl volume is climbing, flat, or suddenly dropped (a drop to zero often means a security plugin or WAF rule quietly started blocking a bot).

For the full request schema and every attribution field, see the WordPress guide and the API reference. To see where WordPress fits among everything crawling the web right now, the list of AI crawlers is the reference.

FAQ

How do I detect GPTBot on WordPress? Add a small must-use plugin in wp-content/mu-plugins/ that forwards each front-end request to a server-side detection endpoint. GPTBot doesn’t run JavaScript, so your analytics plugin can’t see it. Detection has to happen server-side, which the mu-plugin enables without any in-process bot logic.

Will a bot-detection plugin slow down my WordPress site? This one won’t. It fires a single non-blocking wp_remote_post ('blocking' => false) and does no detection work in PHP. Classification happens on Kitbase’s side. That’s the opposite of heavier marketplace bot plugins, which run rule matching and logging inside your PHP process on every request.

Why use a must-use plugin instead of a regular plugin? A must-use plugin loads before regular plugins, runs on every request, and can’t be deactivated from the admin so your bot coverage survives theme switches, plugin updates, and accidental clicks. A regular plugin can be toggled off, taking your coverage with it.

Can I put this in functions.php instead? Yes, the same snippet works in your theme’s functions.php, but it becomes tied to the active theme and disappears when you switch themes. A must-use plugin is theme-independent, which is why it’s the recommended placement.

Does this store my human visitors’ data? No. Human requests are classified in memory and discarded. Only bot and crawler traffic is stored. IPs on stored bot hits are used for geolocation and dropped unless you explicitly enable IP logging.


Want to see every AI bot crawling your WordPress site — verified and per-page? Start your free trial — 7 days, no credit card required — and the setup guide has data flowing in minutes.