Intégrations → Node.js
Intégration Node.js
Middleware Express, hook Fastify, ou simple fetch(). Asynchrone, sans dépendances, fonctionne sur Vercel comme en auto-hébergé.
Middleware Express
Ajoutez zerobot.js et app.use(zerobot) avant vos routes :
// zerobot.js const LICENSE = process.env.ZEROBOT_KEY; const DOMAIN = process.env.ZEROBOT_DOMAIN; async function zerobot(req, res, next) { try { const ip = req.headers['cf-connecting-ip'] || req.ip; const url = 'https://api.zerobot.info/v3/openapi?' + new URLSearchParams({ license: LICENSE, ip, domain: DOMAIN, useragent: req.headers['user-agent'] || '', }); const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 5000); const r = await fetch(url, { signal: controller.signal }); clearTimeout(timeout); const data = await r.json(); if (data.is_bot) { return res.status(403).send(`Blocked: ${data.reason}`); } } catch (err) { // Fail open on timeout / network error console.warn('ZeroBot unreachable, failing open', err.message); } next(); } module.exports = zerobot;
// app.js const express = require('express'); const zerobot = require('./zerobot'); const app = express(); app.use(zerobot); // screens every request app.get('/', (req, res) => res.send('Hello, human!')); app.listen(3000);
Hook Fastify
const fastify = require('fastify')(); fastify.addHook('onRequest', async (req, reply) => { const url = 'https://api.zerobot.info/v3/openapi?' + new URLSearchParams({ license: process.env.ZEROBOT_KEY, ip: req.ip, domain: process.env.ZEROBOT_DOMAIN, useragent: req.headers['user-agent'] ?? '', }); const res = await fetch(url, { signal: AbortSignal.timeout(5000) }); const data = await res.json(); if (data.is_bot) { reply.code(403).send({ error: data.reason }); } });
Middleware Next.js (App Router)
// middleware.ts — runs on every request at the edge import { NextRequest, NextResponse } from 'next/server'; export async function middleware(req: NextRequest) { const ip = req.headers.get('cf-connecting-ip') || req.ip || ''; const url = 'https://api.zerobot.info/v3/openapi?' + new URLSearchParams({ license: process.env.ZEROBOT_KEY!, ip, domain: process.env.ZEROBOT_DOMAIN!, useragent: req.headers.get('user-agent') || '', }); const data = await fetch(url).then(r => r.json()).catch(() => ({})); if (data.is_bot) { return new NextResponse(`Blocked: ${data.reason}`, { status: 403 }); } }
Mise en cache (recommandé)
Pour éviter un appel API à chaque page vue, mettez en cache le verdict par IP pendant 1 à 24 heures. Map en mémoire pour une seule instance, Redis pour un cluster :
const cache = new Map(); const TTL = 24 * 3600 * 1000; // 24h async function screen(req) { const ip = req.ip; const hit = cache.get(ip); if (hit && hit.expires > Date.now()) return hit.verdict; const data = await fetch(/* as above */).then(r => r.json()); cache.set(ip, { verdict: data, expires: Date.now() + TTL }); return data; }