Skip to content

Next.js Middleware

@webdecoy/nextjs wraps the Node SDK for Next.js: edge middleware that runs before every matched request, a wrapper for individual API routes, and captcha route handlers. The middleware runs in monitor mode by default: verdicts are recorded and reported, and every request is served. Set mode: 'enforce' to answer blocking verdicts with a 403 (or your onBlocked handler).

For package capabilities and positioning, see the Next.js bot detection product page.

Terminal window
npm install @webdecoy/nextjs @webdecoy/node
middleware.ts
import { withWebDecoy } from '@webdecoy/nextjs';
import { NextResponse } from 'next/server';
export default withWebDecoy({
apiKey: process.env.WEBDECOY_API_KEY!,
threshold: 70,
// mode: 'enforce', // default is 'monitor': nothing is blocked
onBlocked: (request, detection) => { // runs only in enforce mode
return NextResponse.json(
{ error: 'Blocked', threat: detection.threat_level },
{ status: 403 }
);
}
});
export const config = {
matcher: ['/api/:path*', '/checkout/:path*']
};

The SDK does not read WEBDECOY_API_KEY on its own. Pass it as apiKey, as above. Without an apiKey the middleware runs local checks only and nothing reports to your dashboard. Create the key under API Keys in the dashboard.

Scope the middleware with Next’s matcher: protect the routes that matter (APIs, login, checkout) and leave static assets untouched.

Send one request with the reserved test User-Agent to a route your matcher covers. It always fires a detection through the real pipeline, works on next dev before you deploy, and shows up labeled Test in the dashboard (excluded from stats and billing):

Terminal window
curl -A "WebDecoy-Test/1.0" http://localhost:3000/api/hello

Within a few seconds a detection with the Test category chip appears on the Detections page. If nothing appears, check that the path is covered by your matcher and that apiKey is passed with your key.

Accepts the core SDK configuration and ProtectOptions (threshold, skipLocalAnalysis, metadata), plus:

Option Default Description
mode 'monitor' 'monitor' records verdicts and serves every request; 'enforce' blocks
trustProxy 1 How many proxies to trust in X-Forwarded-For (read from the right): a hop count, 'cloudflare', 'railway', or proxy CIDRs. Set 2 behind a CDN in front of your platform
getIP Derived from trustProxy Custom IP extraction (overrides trustProxy)
onBlocked 403 JSON response Custom NextResponse for blocked requests (enforce mode only)
onError Log and allow (fail open) Custom error handler
skipPaths None Paths to skip

withBotProtection wraps one Pages Router API handler instead of running as global middleware. Unlike the middleware it has no monitor mode: a request whose verdict is not allowed gets a 403 (or a rule’s refusal). blockThreshold defaults to 80.

import { withBotProtection } from '@webdecoy/nextjs';
async function handler(req, res) {
res.json({ message: 'Protected content' });
}
export default withBotProtection(handler, {
apiKey: process.env.WEBDECOY_API_KEY!,
blockThreshold: 70,
});

createCaptchaHandler generates the route handlers the Browser Client widget needs for the self-hosted captcha flow. Mount it as a catch-all App Router route:

app/__webdecoy/[...webdecoy]/route.ts
import { createCaptchaHandler } from '@webdecoy/nextjs';
export const { GET, POST } = createCaptchaHandler({
secret: process.env.WEBDECOY_SECRET!,
});

  • Node SDK: the core API, configuration, and detection response
  • Browser Client: the widget for the captcha flow