Spam filtering

The honeypot, captcha, Risk and the content check, and what each does to a submission.

Every submission is screened before it is delivered. Spam is answered exactly like a success, so whoever sent it learns nothing; you find it on the form's Spam and Held tabs, or with coss.forms.submissions.list(formId, { status: ["spam", "held"] }).

The honeypot

A field people never see (hide it with CSS) and bots fill in. A submission that fills it is spam (spam_reason: "honeypot") at once: no Risk assessment, no files kept, no webhook. It is _gotcha unless you name another with spam.honeypot_field.

Risk

Every other submission is a Risk assessment in the form's environment: a custom event named form_submission, with the submitter's email (submitter.email_field), IP, user agent, captcha token, coss/device token and the text they wrote (label: value per field). It is in your Risk log like any assessment and uses your rules, lists, thresholds and velocity counters, so you can write rules for forms (event_name is form_submission).

A review also sends risk.assessment.review to your webhooks, like any assessment. If Risk can't be reached, the submission is delivered (Risk fails open).

The content check

Risk classifies the submission's text in four categories (spam, phishing, malware, fraud). A submission scoring at least spam.content_threshold (default 0.9) in any of them is spam (spam_reason: "content"), whatever your risk settings' own content thresholds say. Set it between 0.5 and 1, or null to leave content to your risk settings. Live content classification is charged like any content check.

Captcha

spam.captcha: "required" makes every submission carry a token from the captcha in the environment's risk settings (Turnstile or hCaptcha: set one up there first). A submission without one, or whose token fails or can't be checked (the provider didn't answer), is refused with a captcha error the submitter sees: a required captcha never lets one through unchecked. Add the widget to your form (its script puts the token in cf-turnstile-response or h-captcha-response), or set spam.captcha_site_key for hosted pages.

Releasing

coss.forms.submissions.release(formId, id) (or Not spam in the dashboard) delivers a held or spam submission as if it had been accepted, and records its Risk assessment's outcome as legitimate, so Risk learns from it.

const {  } = await ...(, );
// data?.status === "accepted"