example · next.js

02 / 06

Next.js spam filter.

Updated May 12, 2026

This Next.js example adds Siftfy spam detection to an App Router contact form. The Route Handler calls `https://api.siftfy.io/v1/predict` server-side with the submitted text, drops messages scored above the response's own `max_confidence`, queues everything from 0.50 up to that ceiling for review, and delivers the rest. The API key stays in environment variables and never reaches the browser.

A Next.js App Router handler that classifies contact-form text server-side before forwarding clean leads.

typescript
// app/api/contact/route.ts
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  const { email, message } = await req.json();
  if (!email || !message) {
    return NextResponse.json({ error: "email and message required" }, { status: 400 });
  }

  let probability = 0;
  let ceiling = null;
  try {
    const resp = await fetch("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;
      ceiling = data.max_confidence ?? null;
    }
  } catch {
    probability = 0;
  }

  // Drop only ABOVE the ceiling the response reports. At the ceiling the score
  // is censored, so a fixed constant never fires on the model's own opinion.
  if (ceiling !== null && probability > ceiling) return NextResponse.json({ ok: true });
  if (probability >= 0.50) await queueForReview({ email, message, probability });
  else await sendLead({ email, message });
  return NextResponse.json({ ok: true });
}

Production notes

  1. 01`max_confidence` is the highest score the model is allowed to return on its own word; only a score above it is more than the model's opinion.
  2. 02Run this only on the server; never expose your Siftfy key to client components.
  3. 03This pattern works on Vercel, Node, or edge runtimes with fetch support.
  4. 04Use 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.

Get a free API key

More patterns: all examples, contact forms, API reference.