Custom rules
Custom rules are a per-form spam filter you maintain. Three lists, evaluated in order, every submission. Anything they match goes to the spam folder with a spam_reason recording which list caught it.
This sits alongside honeypot, rate limit, captcha, Akismet, and AI moderation. It's not a replacement for any of them — it's the layer where you encode the patterns you keep seeing.
The three lists
Configured per form under Settings → Spam → Custom rules. The shape:
{
"blocked_emails": ["spammer@example.com", "noreply@yandex.ru"],
"keywords": ["loan", "viagra", "crypto investment"],
"regex": ["/\\b[A-Z0-9]{20,}\\b/", "/(\\bhttps?:\\/\\/[^\\s]+){3,}/i"]
}
blocked_emails
Exact matches against any email-shaped value in the payload. Case-insensitive. Use it to block a specific sender or domain you've seen before.
keywords
Case-insensitive substring matches against every string value in the payload, all flattened into one big haystack. Good for blocking topical spam (crypto, loan, seo audit) without writing regex.
regex
Full PCRE patterns, including delimiters and flags (e.g. /viagra/i). Matched against the same flattened haystack as keywords. Use it when substring isn't enough — you need anchors, character classes, or quantifiers.
Bad regex doesn't crash submissions. We log it as custom_rules.regex.invalid and skip the rule. Check read-log-entries if you suspect a pattern is silently dropped.
Evaluation order
Three checks, short-circuit at the first match:
blocked_emailsagainst payload values.keywordsagainst the flattened haystack.regexagainst the flattened haystack.
The match wins, the submission gets status = spam, and the spam_reason column records which rule fired:
rule:blocked_email:spammer@example.comrule:keyword:crypto investmentrule:regex(we don't store which pattern, to keep submissions table small)
Examples
Crypto spam
Blocks the most common patterns we see in contact forms.
{
"keywords": [
"crypto", "bitcoin", "ethereum",
"investment opportunity",
"dm me on telegram"
]
}
Link stuffing
Catch payloads with three or more URLs — usually SEO spam or affiliate dumps.
{
"regex": [
"/(\\bhttps?:\\/\\/[^\\s]+){3,}/i"
]
}
Disposable email domains
Block known throwaway-mail providers at the form level.
{
"regex": [
"/@(?:mailinator|guerrillamail|10minutemail|tempr\\.email|yopmail)\\./i"
]
}
Cyrillic-heavy submissions
If your audience is anglophone but you keep seeing Russian-language spam:
{
"regex": [
"/[Ѐ-ӿ]{20,}/u"
]
}
Rule limits
- 100 entries per list.
- 500 chars per regex pattern.
- 200 chars per keyword.
- 200 chars per blocked email.
Hit any of those and the form save returns 422 with a per-rule error.
Recovering false positives
If a real submission gets caught by a rule, click Mark not spam on the row in the spam folder. The submission moves to the inbox. The rule itself stays — fix it (or remove it) in the form settings.
What's next
- Spam → — the folder where caught submissions land
- Validation → — schema-level field rules (different layer)
- Submissions overview → — full pipeline diagram