Package Exports
- bot-detection
- bot-detection/auto
- bot-detection/client
- bot-detection/next
- bot-detection/server
Readme
bot-detection
Client and server bot detection utilities with Express middleware, simple heuristics, and an optional ML scoring hook.
Features
- Client: user-agent checks, interaction tracking (mouse/keyboard/touch), JS execution proof, timezone, screen, DPR, WebGL vendor/renderer, Canvas hash.
- Server: Express middleware for heuristic checks (missing headers, headless UA, no interaction), simple rate check, session storage (in-memory), and telemetry endpoint.
- Optional ML: Pluggable prediction (default tiny logistic regression) using features such as mouse speed/counts, screen, DPR, timezone, JS enablement.
Install
npm install bot-detectionQuick Start
- Client (bundled app)
import { initClient, sendTelemetry } from "bot-detection/client";
const { stop } = initClient({
sampleMs: 2000,
onUpdate(fp) {
// Ship signals to your backend for scoring
sendTelemetry("/_bot/telemetry", fp);
},
});- Server (Express)
import express from "express";
import cookieParser from "cookie-parser";
import bodyParser from "body-parser";
import { server as bot } from "bot-detection";
const app = express();
app.use(cookieParser());
app.use(bodyParser.json());
const { middleware, router } = bot.createBotDetector({
telemetryPath: "/_bot/telemetry",
ml: { enabled: true },
});
app.use(middleware);
app.post("/_bot/telemetry", router);Test environment
- Build and run unit tests (Node built-in runner):
npm test- Demo Express app:
- Build the package:
npm run build - Install demo deps:
cd examples/express-demo && npm install - Run the demo:
node ../express-demo/server.js(from repo root:npm run demo) - Open
http://localhost:3000and interact with the page
- Build the package:
Publishing to npm
- Set the package name
- Update
nameinpackage.jsonto your real scope (e.g.,"@acme/bot-detection") or unscoped name (e.g.,"bot-detection").
- Build the package
npm run build- Login and publish
npm login
# For scoped packages publish publicly
npm publish --access public
# For unscoped packages
# npm publish- Versioning
- Use
npm version patch|minor|majorto bump versions before publishing.
After publishing, consumers can install and use:
npm install bot-detectionZero‑Config Client (React)
- Add one import in your app’s root client file and you’re done:
import 'bot-detection/auto';- Optional: configure before import to enable telemetry POSTs (off by default):
;(window as any).__BOT_DETECTION__ = {
// Telemetry is OFF by default. To enable, set both:
telemetryEnabled: true,
telemetryUrl: '/api/bot/telemetry',
sampleMs: 2000,
attachFetch: true, // auto attach base64 header to same‑origin fetch
attachXHR: false, // set to true to patch XHR as well
headerName: 'x-bot-features',
};
import 'bot-detection/auto';Next.js Middleware Helper
Use our helper in middleware.ts to add bot headers to every response without creating any API routes:
// src/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { evaluateRequest } from 'bot-detection/next';
export function middleware(request: NextRequest) {
const base64 = request.headers.get('x-bot-features');
const { headers } = evaluateRequest(request as any, base64);
const res = NextResponse.next();
for (const [k, v] of Object.entries(headers)) res.headers.set(k, v);
return res;
}Notes
- The client
autoimport attachesx-bot-featuresautomatically to same‑origin fetches. - If you don’t import the client, you still get server‑only heuristics using request headers (UA, accept‑language, etc.).
React: one‑liner auto install
- Add this import once in your app layout (Vite/CRA/Next client component):
import 'bot-detection/auto';- Optional: configure before import (telemetry URL, header name, sample rate):
// e.g., src/bot-detect.ts (import this early, like in your root layout)
;(window as any).__BOT_DETECTION__ = {
telemetryUrl: '/_bot/telemetry', // your backend endpoint
sampleMs: 2000,
attachFetch: true,
attachXHR: false,
headerName: 'x-bot-features',
};
import 'bot-detection/auto';- What it does automatically:
- Starts client fingerprint + interaction tracking.
- Sends telemetry every
sampleMstotelemetryUrl. - Attaches a base64 telemetry header to all same‑origin
fetchcalls (x-bot-features).
Notes for Next.js
- App Router: create a small
use clientcomponent added toapp/layout.tsxand import'bot-detection/auto'inside it. - Pages Router: import
'bot-detection/auto'inpages/_app.tsx.
Client usage
import { initClient, sendTelemetry } from "bot-detection/client";
// Start collecting fingerprint + interactions and periodically update
const { stop } = initClient({
sampleMs: 2000,
onUpdate(fp) {
// Optionally send to server endpoint
sendTelemetry("/_bot/telemetry", fp);
},
});
// Call stop() to remove listenersIf you prefer to control sending, you can call collectFingerprint and send data yourself.
Server usage (Express)
import express from "express";
import cookieParser from "cookie-parser";
import bodyParser from "body-parser";
import { server as bot } from "bot-detection";
const app = express();
app.use(cookieParser());
app.use(bodyParser.json({ limit: "50kb" }));
const { middleware, router } = bot.createBotDetector({
telemetryPath: "/_bot/telemetry",
rateLimit: { windowMs: 60_000, max: 120 },
ml: { enabled: true },
});
app.use(middleware);
app.post("/_bot/telemetry", router); // or: app.use(router) and ensure body json parser runs before
app.get("/protected", (req, res) => {
const result = (req as any).botDetection;
if (result?.isBot) return res.status(403).send("Bots not allowed");
res.send("Hello human");
});
app.listen(3000);Sending features via header instead of body
You can also pass client features in a base64-encoded JSON header and the middleware will consume it:
// client side
import { collectFingerprint } from "bot-detection/client";
const stop = collectFingerprint({
onUpdate(fp) {
const hdr = btoa(JSON.stringify(fp));
fetch("/protected", { headers: { "x-bot-features": hdr } });
},
});Heuristics
- Missing headers:
user-agent,accept,accept-languageincrease risk. - Headless UA keywords trigger higher risk.
- No interaction over time suggests automation.
- Rate limiting: excessive requests per IP/UA within a window increases risk.
ML hook
You can inject your own model:
import { server as bot } from "bot-detection";
const { middleware } = bot.createBotDetector({
ml: {
enabled: true,
predict: (features) => {
// return { score: 0..1, label: 'bot' | 'human' }
return { score: Math.random(), label: "human" };
},
},
});Types
All relevant types are exported from the package root.
Notes
- The in-memory session store is suitable for single-instance demos. Use a distributed store for production.
- The default ML is intentionally simple and acts as a placeholder.
- For best results, mount
cookie-parserandbody-parserbefore the middleware/router.