Spam classification
A submission lands in spam when one (or more) of three layers flagged it. Knowing which layer is what makes triage fast.
The three layers
Submissions pass through three independent filters before being saved. Any one of them can route the submission to the spam folder. The first one that flags wins, and the field spam_reason records which layer fired.
| Layer | Triggers when | spam_reason value |
|---|---|---|
| 1. Captcha | hCaptcha or reCAPTCHA token is missing or invalid | (returns 422 — never lands as spam) |
| 2. Honeypot | A hidden honeypot field was filled in | honeypot |
| 3. Akismet | Akismet's classifier returns is_spam: true |
akismet |
| 4. Heuristics | Internal rules — repeated identical payloads, blocked-domain lists, suspicious link density | heuristics:<rule> |
| 5. AI moderation | AI moderation score crosses the threshold (default 80/100) | ai_moderation:<score> |
| 6. Custom rules | A custom rule on the form matched | rule:<rule_id> |
| Manual | You marked it as spam from the dashboard or via the MCP mark_as_spam tool |
manual:<source> |
Captcha failures don't actually create a spam record — they're rejected at the wall with a 422. Everything below the captcha layer accepts the submission and routes it.
Where to see the reason
In the dashboard:
- Open the form's submissions tab
- Switch to the Spam folder (top-right tab)
- Click any submission
The detail panel shows spam_reason near the top. Hover for the human-readable description.
Via the API:
GET /api/v1/forms/{public_id}/submissions/{id}
The response includes spam_reason and (when the layer was AI moderation) ai_moderation_score.
Via MCP:
get_submission { id: "01HFXX..." }
Same field surfaces.
Marking something not-spam
Three ways:
- Dashboard. Open the submission → click Not spam. It moves to
receivedand the reason is cleared. - API.
PATCH /api/v1/forms/{public_id}/submissions/{id}with{ "status": "received" }. - MCP.
update_submission { id, status: "received" }orbulk_submissions { ids: [...], action: "mark_not_spam" }for batches up to 500.
Marking not-spam moves the record but doesn't suppress future flags. The next submission from the same source might re-flag for the same reason.
We don't retrain on your corrections
Be honest, useful answer: marking not-spam doesn't feed back into our spam classifiers. The external spam classifier is a black box that doesn't accept per-customer feedback signals. Our heuristics are static rules. AI moderation runs on a frozen prompt + score threshold.
If a specific kind of legitimate submission keeps getting flagged, the right move is:
- For Akismet false positives: mark the sending domain or email as a custom rule allow-list (Form → Spam → Custom rules → "always allow if email matches…").
- For honeypot false positives: check that your form isn't auto-filling honeypot fields via password manager. Rename the honeypot field if it does.
- For AI moderation false positives: raise the threshold per-form (Form → AI moderation → score threshold). Default 80; raising to 90 dramatically reduces false positives at the cost of letting some borderline content through.
These are knobs you control. Marking individual submissions, while useful for cleaning your inbox, does not adjust those thresholds for future submissions.
Marking as spam manually
If something legitimate-looking gets through and you want it in spam:
- Dashboard. Submission → Mark as spam.
- MCP.
mark_as_spam { id }— setsstatus: spam,spam_reason: manual:mcp.
Manual spam is identical to auto-flagged spam in the database. It just has manual:<source> as the reason for audit clarity.
Disabling a layer
You can turn off any of the auto-classification layers per form, under Form → Spam protection:
- Captcha: required for hosted forms; optional for legacy forms (we recommend keeping it on)
- Honeypot: on by default
- Akismet: on by default; opt-out is a single toggle. See sub-processors for the regional and DPA implications
- AI moderation: Pro+ only; on by default
- Heuristics: on for all forms; not configurable individually, but the underlying rules are documented at Spam → How it works
Disabling layers means more spam in your inbox. We don't recommend disabling more than one at a time.
What's next
- Spam protection overview → — full architecture
- Custom rules → — allow-list and block-list logic
- AI moderation → — the score-based layer
- Common issues → — top stumbles