Modern Koa middleware for intelligent bot detection using the industry-standard isbot library. Detect search engines, crawlers, AI bots (ChatGPT, Claude, Perplexity), and thousands of other bots with TypeScript support and zero configuration.
- ๐ค Comprehensive Bot Detection - Detects thousands of bots including Google, Bing, ChatGPT, Claude, Perplexity, and more
- ๐ฆ Zero Config - Works out of the box with sensible defaults
- ๐ฏ TypeScript First - Full type safety and IntelliSense support
- โก High Performance - Built-in caching and optimizations
- ๐ง Highly Customizable - Extend detection with custom patterns
- ๐ก๏ธ Security Hardened - Input validation and DoS protection
- ๐ Analytics Friendly - Callbacks for tracking and logging
- ๐ณ Tree-shakeable - ESM and CJS support with optimal bundling
- โ Battle Tested - 100% test coverage with Vitest
npm install @duyetdev/koa-isbotimport Koa from 'koa';
import { koaIsBot } from '@duyetdev/koa-isbot';
const app = new Koa();
// Add the middleware
app.use(koaIsBot());
// Use bot detection in your routes
app.use((ctx) => {
if (ctx.state.isBot?.isBot) {
console.log(`Bot detected: ${ctx.state.isBot.botName}`);
// Serve static pre-rendered content
} else {
// Serve dynamic content
}
});
app.listen(3000);Creates a Koa middleware for bot detection.
interface KoaIsBotOptions {
/**
* Custom bot patterns to add to detection
* @example ['mybot', /customcrawler/i]
*/
customPatterns?: (string | RegExp)[];
/**
* Patterns to exclude from bot detection
* @example ['chrome-lighthouse']
*/
excludePatterns?: string[];
/**
* Where to store the detection result in Koa context
* @default 'isBot'
*/
stateKey?: string;
/**
* Enable result caching for performance
* @default true
*/
cache?: boolean;
/**
* Maximum cache size (number of entries)
* @default 1000
*/
cacheSize?: number;
/**
* Cache TTL in milliseconds
* @default 3600000 (1 hour)
*/
cacheTTL?: number;
/**
* Callback when a bot is detected
*/
onBotDetected?: (ctx: Context, result: BotDetectionResult) => void | Promise<void>;
/**
* Callback for all requests
*/
onDetection?: (ctx: Context, result: BotDetectionResult) => void | Promise<void>;
/**
* Custom user agent extraction function
* @default (ctx) => ctx.request.headers['user-agent']
*/
getUserAgent?: (ctx: Context) => string | undefined;
}The bot detection result is stored in ctx.state.isBot (or custom stateKey):
interface BotDetectionResult {
/** Whether a bot was detected */
isBot: boolean;
/** Name of the detected bot */
botName: string | null;
/** All detected bot patterns */
botPatterns: string[];
/** The user agent string analyzed */
userAgent: string;
}import Koa from 'koa';
import { koaIsBot } from '@duyetdev/koa-isbot';
const app = new Koa();
app.use(koaIsBot());
app.use((ctx) => {
const { isBot, botName } = ctx.state.isBot;
ctx.body = isBot
? `Hello ${botName}! Here's your optimized content.`
: 'Hello human! Welcome to our site.';
});Add detection for your own bots or crawlers:
app.use(koaIsBot({
customPatterns: [
'my-internal-bot',
/company-crawler/i,
'monitoring-service'
]
}));Exclude certain bots from detection (e.g., Lighthouse for performance testing):
app.use(koaIsBot({
excludePatterns: ['chrome-lighthouse']
}));Track bot visits for analytics:
app.use(koaIsBot({
onBotDetected: async (ctx, result) => {
console.log(`๐ค Bot visit: ${result.botName} on ${ctx.path}`);
// Send to analytics
await analytics.track('bot_visit', {
bot: result.botName,
path: ctx.path,
timestamp: new Date()
});
},
onDetection: async (ctx, result) => {
// Track all requests (bots and humans)
await analytics.track('page_view', {
isBot: result.isBot,
path: ctx.path
});
}
}));Store the result in a custom location:
app.use(koaIsBot({ stateKey: 'bot' }));
app.use((ctx) => {
if (ctx.state.bot?.isBot) {
// Access via custom key
}
});Configure caching for high-traffic applications:
app.use(koaIsBot({
cache: true,
cacheSize: 5000, // Store up to 5000 unique user agents
cacheTTL: 7200000 // 2 hours cache lifetime
}));Serve pre-rendered content to search engines:
app.use(koaIsBot());
app.use(async (ctx) => {
if (ctx.state.isBot?.isBot) {
// Serve pre-rendered HTML for SEO
ctx.body = await prerenderService.getPage(ctx.path);
ctx.set('Cache-Control', 'public, max-age=3600');
} else {
// Serve SPA for humans
ctx.body = await fs.readFile('index.html');
}
});Extract user agent from custom headers (useful with proxies):
app.use(koaIsBot({
getUserAgent: (ctx) => {
// Check custom header from proxy
return ctx.get('X-Original-User-Agent') ||
ctx.get('User-Agent') ||
'';
}
}));This middleware uses isbot which detects thousands of bots including:
Search Engines:
- Googlebot, Bingbot, Yandex, Baidu, DuckDuckBot
- Yahoo Slurp, Exabot, and many more
AI Assistants & Crawlers:
- ChatGPT-User, GPTBot (OpenAI)
- Claude-Web (Anthropic)
- PerplexityBot
- Applebot, Facebookbot
Social Media:
- TwitterBot, LinkedInBot, TelegramBot
- SlackBot, PinterestBot, WhatsApp
Development & Monitoring:
- Postman, curl, wget
- Pingdom, UptimeRobot, StatusCake
- Chrome Lighthouse (optional)
And thousands more! See the full list.
Version 2.0 is a complete rewrite with breaking changes. Here's how to migrate:
const isBot = require('koa-isbot');
app.use(isBot());
app.use(async (ctx, next) => {
console.log(ctx.isBot); // 'googlebot' or null
});import { koaIsBot } from '@duyetdev/koa-isbot';
app.use(koaIsBot());
app.use((ctx) => {
console.log(ctx.state.isBot); // BotDetectionResult object
// {
// isBot: true,
// botName: 'googlebot',
// botPatterns: ['googlebot'],
// userAgent: '...'
// }
});- ES Modules: Now uses ESM (with CJS support)
- TypeScript: Full TypeScript support with types
- Result Location: Moved from
ctx.isBottoctx.state.isBot - Result Format: Now returns detailed object instead of string/null
- Detection: Uses isbot library (thousands of patterns vs. 15)
- Features: Added caching, callbacks, customization
See examples/advanced.ts for a complete example with:
- Custom patterns and exclusions
- Analytics integration
- Performance monitoring
- Different content serving
- Error handling
# Run the advanced example
npm install
npm run build
node examples/advanced.ts# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watch# Install dependencies
npm install
# Build the project
npm run build
# Type check
npm run type-check
# Lint
npm run lint
# Format code
npm run format- Cached requests: < 1ms overhead
- Uncached requests: < 5ms overhead
- Memory: Automatic LRU cache eviction
- Security: Input sanitization and length limits
- User agent strings are limited to 2048 characters to prevent DoS
- Input is sanitized before regex matching
- Cache size is bounded with LRU eviction
- No eval() or unsafe operations
Contributions are welcome! Please see CONTRIBUTING.md for details.
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Ensure all tests pass (
npm test) - Submit a pull request
MIT License - Copyright (c) 2016-2025 Van-Duyet Le
See LICENSE for details.
- Built on top of isbot by Omri Lotan
- Inspired by the original koa-isbot concept
- TypeScript types for Koa
- ๐ Report bugs
- ๐ฌ Ask questions
- โญ Star the repo if you find it useful!
- isbot - The underlying bot detection library
- Koa - Next generation web framework for Node.js
- koa-useragent - User agent parser for Koa
Made with โค๏ธ by Van-Duyet Le