A Next.js App Router handler that classifies contact-form text server-side before forwarding clean leads.
route.tstypescript
typescript
// app/api/contact/route.tsimport { NextResponse } from"next/server";
exportasyncfunctionPOST(req: Request) {
const { email, message } = await req.json();
if (!email || !message) {
returnNextResponse.json({ error: "email and message required" }, { status: 400 });
}
let probability = 0;
try {
const resp = awaitfetch("https://api.siftfy.io/v1/predict", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.SIFTFY_KEY!,
},
body: JSON.stringify({ text: message }),
signal: AbortSignal.timeout(2000),
});
if (resp.ok) {
const data = await resp.json();
probability = data.spam_probability;
}
} catch {
probability = 0;
}
if (probability >= 0.85) returnNextResponse.json({ ok: true });
if (probability >= 0.50) awaitqueueForReview({ email, message, probability });
elseawaitsendLead({ email, message });
returnNextResponse.json({ ok: true });
}
Production notes
01Run this only on the server; never expose your Siftfy key to client components.
02This pattern works on Vercel, Node, or edge runtimes with fetch support.
03Use the same route for Webflow or static-site form posts if you already deploy Next.js.
Common questions
How do I add Siftfy spam detection to a Next.js contact form?
Create a Route Handler at `app/api/contact/route.ts`, POST the message text to `https://api.siftfy.io/v1/predict` with your API key in the `X-API-Key` header, and branch on the returned `spam_probability`. The full handler is shown above.
Where should I store the Siftfy API key in Next.js?
Use an environment variable that does not start with `NEXT_PUBLIC_` so it stays server-only. Read it inside the Route Handler as `process.env.SIFTFY_KEY`. Client components must never see the key.
Does this Next.js spam filter run on the Edge runtime?
Yes. The handler uses the Web Fetch API and AbortSignal.timeout, both of which work on Vercel Edge, Cloudflare, and Node runtimes. Set `export const runtime = 'edge'` if you want edge execution.
Should I tell the user that a submission was flagged as spam?
No. Return the same success response for spam and clean messages so spammers can't probe your thresholds. Log the action server-side instead and surface it in your moderation dashboard.