Node.js Integration

Track bot and AI crawler visits from any Node.js application. Works with Express, Fastify, Next.js, Koa, and any Node.js HTTP server.

Time to set up: ~2 minutes

Prerequisites

Express / Connect

Add the middleware to your Express app:

const BOTSIGHTS_API_KEY = 'YOUR_API_KEY_HERE';
const BOTSIGHTS_API_URL = 'https://in.botsights.com/v1/log';

const SKIP_EXT = new Set([
  'css','js','png','jpg','jpeg','gif','svg','webp','avif',
  'ico','woff','woff2','ttf','eot','map','mp4','webm','mp3',
]);

function botsights(req, res, next) {
  const startTime = Date.now();
  const ext = req.path.split('.').pop();
  if (ext && SKIP_EXT.has(ext.toLowerCase())) return next();

  const originalEnd = res.end;
  res.end = function (...args) {
    originalEnd.apply(res, args);
    fetch(BOTSIGHTS_API_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        api_key: BOTSIGHTS_API_KEY,
        ua: req.headers['user-agent'] || '',
        url: req.originalUrl || req.url,
        ip: req.headers['cf-connecting-ip']
          || req.headers['x-forwarded-for']?.split(',')[0]?.trim()
          || req.socket?.remoteAddress || '',
        referer: req.headers['referer'] || '',
        status_code: res.statusCode,
        duration_ms: Date.now() - startTime,
        content_type: res.getHeader?.('content-type') || '',
        http_method: req.method,
        source: 'nodejs',
      }),
    }).catch(() => {});
  };
  next();
}

// Use it:
app.use(botsights);

Next.js (Middleware)

For Next.js apps not hosted on Cloudflare, add to middleware.ts:

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

const BOTSIGHTS_API_KEY = 'YOUR_API_KEY_HERE';
const BOTSIGHTS_API_URL = 'https://in.botsights.com/v1/log';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();
  const startTime = Date.now();

  // Skip static assets
  const ext = request.nextUrl.pathname.split('.').pop() || '';
  const skip = ['css','js','png','jpg','svg','ico','woff','woff2'];
  if (skip.includes(ext)) return response;

  // Send analytics after response (non-blocking via waitUntil if available)
  const data = {
    api_key: BOTSIGHTS_API_KEY,
    ua: request.headers.get('user-agent') || '',
    url: request.nextUrl.pathname + request.nextUrl.search,
    ip: request.headers.get('x-forwarded-for')?.split(',')[0] || '',
    referer: request.headers.get('referer') || '',
    http_method: request.method,
    source: 'nodejs_nextjs',
  };

  fetch(BOTSIGHTS_API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  }).catch(() => {});

  return response;
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

How It Works

The middleware intercepts every incoming request, measures the response time, and sends analytics to BotSights after the response is sent. Static assets are automatically skipped.

Troubleshooting

No data appearing?