use case · webflow
Webflow form spam protection.
Updated May 12, 2026
Webflow ships zero spam filtering on its native forms. The default response — drop reCAPTCHA on the page — adds friction, hurts conversion, and still misses the headless-browser bots. Route the form-submission webhook through Siftfy instead and you get a calibrated probability per submission with no UX change.
Why webhook-fronting beats on-page CAPTCHA
Every Webflow plan supports a server-side form webhook (Project Settings → Forms → Form Submissions URL). Anything you put behind that URL runs after the user submits but before the data lands in your CRM or inbox — which is exactly where spam classification belongs. The user sees the same confirmation message either way; you just decide whether the lead is real before paying it any attention.
On-page CAPTCHA, by contrast, is a tax on every legitimate visitor and is bypassed by any bot running a real headless browser. Modern spam isn't dumb form-fillers — it's content. Classify the content.
Drop-in Cloudflare Worker
The pattern below is a 30-line Cloudflare Worker that sits between Webflow and your real destination. Same shape works on Vercel Functions, Netlify Functions, AWS Lambda, or a tiny Express app you already run. Three thresholds — definitely-spam (drop), maybe (queue), clean (deliver) — and a 2-second timeout so a slow Siftfy call never makes the form-submission UX feel broken.
// Cloudflare Worker — fronts Webflow's form webhook with Siftfy.
// Configure Webflow Project Settings > Forms > Form Submissions URL to
// https://your-worker.workers.dev/webflow
const SPAM_THRESHOLD = 0.85; // hard drop above this
const QUEUE_THRESHOLD = 0.50; // human review between
export default {
async fetch(req, env) {
if (req.method !== "POST") return new Response("method", { status: 405 });
// Webflow posts form fields as application/x-www-form-urlencoded.
const form = await req.formData();
const message = String(form.get("message") ?? form.get("description") ?? "");
const email = String(form.get("email") ?? "");
let probability = 0;
try {
const resp = await fetch("https://api.siftfy.io/v1/predict", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": env.SIFTFY_KEY,
},
body: JSON.stringify({ text: message }),
signal: AbortSignal.timeout(2000),
});
if (resp.ok) {
({ spam_probability: probability } = await resp.json());
}
} catch {
// Fall open on transport failure — don't drop a real lead.
}
if (probability >= SPAM_THRESHOLD) {
// Always 200 to Webflow, even on a hard block. The form sees "thanks"
// and the spammer doesn't learn the threshold.
return new Response("ok", { status: 200 });
}
// Forward clean / borderline submissions to your real handler
// (CRM, email service, Airtable, n8n, whatever).
await env.DESTINATION.fetch(`https://hooks.example.com/lead?score=${probability}`, {
method: "POST",
body: JSON.stringify({ email, message, probability }),
headers: { "Content-Type": "application/json" },
});
return new Response("ok", { status: 200 });
},
};Wiring it up in Webflow
- Deploy the worker (or function) to a public HTTPS URL.
- In Webflow, open Project Settings → Forms → Form Submissions URL and paste the public URL.
- Test with a clean submission and a junk submission — junk should be silently dropped, clean should land at your destination.
- Set a
SIFTFY_KEYsecret on the worker (Cloudflare Dashboard → Workers → Variables → Encrypt).
Webflow's native "Email me on form submission" still fires for clean and borderline submissions because the worker forwards them to your email destination as the last step.
Edge cases worth handling
- Multiple form types. Webflow sends a
namefield identifying the form. Branch on it if you classify a contact form differently from a newsletter signup (newsletters tolerate higher false positives). - Long message bodies. Siftfy truncates input above its model context — for long bug reports or product feedback, you don't need the entire body, just the first 500 words. Slice client-side.
- Multilingual forms. The model is trained primarily on English. Raise the block threshold to ~0.92 if you serve other languages until coverage improves.
- Don't reveal the score. Always return 200 to Webflow. A 4xx makes Webflow show a generic error to the user and tells the spammer their content was flagged.
10,000 submissions / month free. Read the /v1/predict reference, or peek at related use cases: contact forms, static sites, headless CMS.