Botkibble
Serves every published post and page as Markdown for AI agents and crawlers. No configuration, no API keys. Activate and it works.
Next Milestone 10
Unlock Exact Install Count
See the precise estimated active installs for this plugin, calculated from real-time ranking data.
- Exact install estimates within tiers
- Track install growth over time
- Milestone progress predictions
Rank Changes
Downloads Growth
Upgrade to Pro
Unlock 30-day, 90-day, and yearly download history charts with a Pro subscription.
Upgrade NowReviews & Ratings
Tracked Keywords
Showing 1 of 1| Keyword | Position | Change | Type | Updated |
|---|---|---|---|---|
| crawlers | 188 | — | Tag | 1 month ago |
Unlock Keyword Analytics
Track keyword rankings, search positions, and discover new ranking opportunities with a Pro subscription.
- Full keyword position tracking
- Historical ranking data
- Competitor keyword analysis
Track This Plugin
Get detailed analytics, keyword tracking, and position alerts delivered to your inbox.
Start Tracking FreePlugin Details
- Version
- 1.3.0
- Last Updated
- Feb 27, 2026
- Requires WP
- 6.0+
- Tested Up To
- 6.9.4
- PHP Version
- 8.2 or higher
- Author
- gregrandall
Support & Rating
- Rating
- ☆ ☆ ☆ ☆ ☆ 0
- Reviews
- 0
- Support Threads
- 0
- Resolved
- 0%
Keywords
Upgrade to Pro
Unlock keyword rankings, search positions, and detailed analytics with a Pro subscription.
Upgrade NowFrequently Asked Questions
Common questions about Botkibble
$types[] = 'docs';
return $types;
} );
Be careful. Only add post types that contain public content. Do not expose post types that may contain private or sensitive data (e.g. WooCommerce orders).
What does the YAML frontmatter include?
Every response starts with a YAML block containing:
title — the post title
date — publish date in ISO 8601 format
type — post type (e.g. post, page)
word_count — word count of the Markdown body
char_count — character count of the Markdown body
tokens — estimated token count (word_count × 1.3)
categories — array of category names (posts only)
tags — array of tag names (posts only, omitted if none)
Example:
---
title: My Post Title
date: '2025-06-01T12:00:00+00:00'
type: post
word_count: 842
char_count: 4981
tokens: 1095
categories:
- Technology
tags:
- wordpress
- markdown
---
$data['excerpt'] = get_the_excerpt( $post );
return $data;
}, 10, 2 );
return 'ai-train=no, search=yes, ai-input=yes';
}, 10, 2 );
Return an empty string to omit the header entirely.
Can I change the token count estimation?
Yes, use the botkibble_token_multiplier filter. The default multiplier of 1.3 (word count × 1.3) comes from Cloudflare's implementation:
add_filter( 'botkibble_token_multiplier', function () {
return 1.5; // Adjusted for a different model's tokenizer
} );
How do I adjust the rate limit?
Cache misses (when a post needs to be converted) are limited to 20 per minute globally. You can change this with the botkibble_regen_rate_limit filter:
add_filter( 'botkibble_regen_rate_limit', function () {
return 50;
} );
// Remove a plugin's wrapper divs
$html = preg_replace( '/<div class="my-plugin-wrapper">(.*?)<\/div>/s', '$1', $html );
return $html;
} );
Can I strip script nodes during conversion?
Yes. Botkibble keeps converter node removal disabled by default (for backward compatibility), but you can opt in with botkibble_converter_remove_nodes:
add_filter( 'botkibble_converter_remove_nodes', function ( $nodes ) {
$nodes = is_array( $nodes ) ? $nodes : [];
$nodes[] = 'script';
return $nodes;
} );
If you also need application/ld+json, extract it in botkibble_clean_html first, then let converter-level script removal clean up any remaining script tags.
How do I modify the body before metrics are calculated?
Use the botkibble_body filter. This is the best place to add content like ld+json that you want included in the word count and token estimation:
add_filter( 'botkibble_body', function ( $body, $post ) {
$json_ld = '<script type="application/ld+json">...</script>';
return $body . "\n\n" . $json_ld;
}, 10, 2 );
return $markdown . "\n\n---\nServed by Botkibble";
}, 10, 2 );
Can I cache multiple Markdown variants (e.g. a slim version)?
Yes. Add ?botkibble_variant=slim when requesting Markdown to generate and serve a separate cached file. To ensure your variants are invalidated on post updates, return them from the botkibble_cache_variants filter:
add_filter( 'botkibble_cache_variants', function ( $variants, $post ) {
$variants[] = 'slim';
return $variants;
}, 10, 2 );
Can I disable the Accept header detection?
Yes, if you only want to serve Markdown via explicit URLs (.md or ?format=markdown), use the botkibble_enable_accept_header filter:
add_filter( 'botkibble_enable_accept_header', '__return_false' );
Does the .md suffix work with all permalink structures?
It works with the most common structures (post name, page hierarchy). Complex date-based permalink structures may require the query parameter or Accept header method instead.
What about password-protected posts?
They return a 403 Forbidden response. There's no point serving a password form to a bot.
What are the response headers?
Content-Type: text/markdown; charset=utf-8
Vary: Accept — tells caches that responses vary by Accept header
X-Markdown-Tokens: <count> — estimated token count (word_count × 1.3)
X-Robots-Tag: noindex — prevents search engines from indexing the Markdown version
Link: <url>; rel="canonical" — points search engines to the original HTML post
Link: <url>; rel="alternate" — advertises the Markdown version for discovery
Content-Signal: ai-train=no, search=yes, ai-input=yes — see contentsignals.org