Express Middleware
@webdecoy/express wraps the Node SDK as Express middleware: every request is analyzed, blocked requests get a 403 by default, and the detection result rides on req.webdecoy.
For package capabilities and positioning, see the Express bot detection product page.
Installation
Section titled “Installation”npm install @webdecoy/express @webdecoy/nodeQuick Start
Section titled “Quick Start”import express from 'express';import { webdecoy } from '@webdecoy/express';
const app = express();
app.use(webdecoy({ threshold: 70, skipPaths: ['/health', '/static'], onBlocked: (req, res, detection) => { res.status(403).json({ error: 'Blocked' }); }}));
app.post('/api/login', (req, res) => { const { decision, confidence, threat_level } = req.webdecoy;
if (decision === 'challenge') { return res.status(429).json({ error: 'Please complete verification' }); }
// Process login...});Verify Your Install
Section titled “Verify Your Install”Send one request with the reserved test User-Agent. It always fires a detection through the real pipeline, works on localhost before you deploy, and shows up labeled Test in the dashboard (excluded from stats and billing):
curl -A "WebDecoy-Test/1.0" http://localhost:3000/Within a few seconds a detection with the Test category chip appears on the Detections page. In the default monitor mode the request is served normally; with mode: 'enforce' the curl gets a 403, so you can see the middleware act from the terminal alone. If nothing appears in the dashboard, check that the middleware is mounted before your routes and that WEBDECOY_API_KEY is set.
Options
Section titled “Options”Extends the core ProtectOptions (threshold, skipLocalAnalysis, metadata) with:
| Option | Default | Description |
|---|---|---|
getIP |
req.ip / x-forwarded-for |
Custom IP extraction |
onBlocked |
403 Forbidden | Custom handler for blocked requests |
onError |
Log and allow (fail open) | Custom error handler |
skipPaths |
None | Paths to skip (health checks, static assets) |
extractTLS |
false |
Capture JA3/JA4 TLS fingerprints from the socket |
rules |
None | Local rules such as tripwire() |
Set a Scraper Trap
Section titled “Set a Scraper Trap”Tripwires run locally, with no API key and no network call. And under session clearance, a tripwire hit from a tokened session feeds the clearance deny-list: the SDK forwards the session’s token with the violation, and the client gets the same durable, rotation-proof lockout as a hosted decoy hit.
With an apiKey, this is already on. The middleware injects a hidden
honeytoken link into your HTML responses and arms the tripwire it points at, with no
wiring and no template edit:
import { webdecoy } from '@webdecoy/express';
app.use(webdecoy({ apiKey: process.env.WEBDECOY_API_KEY, skipPaths: ['/health', '/static']}));The path is derived from your API key by HMAC, so every replica advertises and
arms the same one. Set honeytoken: false to opt out.
Only full text/html responses are rewritten. JSON, text and downloads are left
alone, and a response that has already committed a Content-Length is skipped so
the body can never truncate at the client.
To place the link yourself, or to add extra bait paths:
import { tripwire, honeytoken } from '@webdecoy/node';
const trap = honeytoken();
app.use(webdecoy({ honeytoken: false, rules: [tripwire({ paths: [trap.path] })],}));
app.get('/', (req, res) => { res.send('<!doctype html><html><body>' + trap.linkHtml + '</body></html>');});Captcha Endpoints
Section titled “Captcha Endpoints”webdecoyCaptcha mounts the self-hosted captcha’s challenge and verify endpoints, which the Browser Client widget talks to:
import { webdecoyCaptcha } from '@webdecoy/express';
app.use(express.json());app.use(webdecoyCaptcha({ secret: process.env.WEBDECOY_SECRET }));Next Steps
Section titled “Next Steps”- Node SDK: the core API, configuration, and detection response
- Browser Client: the widget for the captcha endpoints