use case · webflow
Add content-level spam scoring to Webflow forms.
Updated July 29, 2026
Native controls are the right baseline for obvious bot traffic. Siftfy adds a separate content decision for forms where the message itself determines whether a submission should be delivered, held for review, or silently discarded.
Choose the integration path that matches your form
A custom form action can send the submission directly to your own HTTPS handler, where it can be classified before delivery. Webflow Apps and automation tools can also forward native submissions to a handler, which is useful when you want Webflow to keep the original record. Confirm the behavior for your workspace before cutover: custom actions bypass Webflow's submission processing and notification emails.
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 small Cloudflare Worker used as the form's custom action and forwarding accepted submissions to your real destination. The 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 used as a Webflow custom form action.
// Point the form action to https://your-worker.workers.dev/webflow.
// A custom action bypasses Webflow's own submission storage and emails,
// so forward accepted submissions to the destination you control.
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.
- Set the form's custom action to the worker URL and use
POST. - 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).
Because a custom action bypasses Webflow's submission storage and notifications, the worker must forward accepted submissions to your inbox, CRM, database, or automation endpoint itself.
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.