WordPress (Contact Form 7)
Protect every Contact Form 7 form from bots, spam, and disposable email addresses with Verifence Shield — no changes to your form templates required.
A drop-in plugin that protects every Contact Form 7 form on your site with Verifence Shield, a honeypot, and optional email validation. It injects the widget and hooks into CF7's built-in spam pipeline, so no changes to your form templates are needed.
What it does
| Protection | How |
|---|---|
| Bot blocking | Invisible proof-of-work challenge + browser fingerprinting via Shield |
| Honeypot | Hidden field injected into every form — bots that fill it are silently blocked |
| Behavioural analysis | Timing, mouse movement, and keystroke variance checked on the Shield side |
| Spam text classification | Message body scored for spam probability (requires spam detection enabled) |
| Email validation | Disposable and role-account addresses blocked via the scan API (optional) |
Requirements
- WordPress 5.8+ and PHP 8.0+
- Contact Form 7 5.5 or higher
- A Verifence account with a Shield site configured
Configuration
In your Verifence dashboard, open Shield Sites, copy the site key and secret key, and set the allowed domain to your WordPress domain. Then, in WordPress under Settings → Verifence Shield, fill in:
| Setting | Description |
|---|---|
| Site Key | Public key from your Shield site |
| Secret Key | Private key — never exposed to browsers |
| API Key | (Optional) Verifence API key for email validation |
| Enable email validation | Blocks disposable email addresses at submission |
| Block role accounts | Also blocks info@, admin@, support@, etc. |
| Spam score threshold | Submissions above this % spam probability are blocked (default: 85) |
| Message field name | The CF7 field name of your message textarea (default: your-message) |
How it works
Browser phase (automatic)
When a page with a CF7 form loads, the plugin injects a .shield-widget element (with your site key) and a honeypot field into every form. The widget renders invisibly, adds its own hidden shield-token field, runs the proof-of-work challenge and behavioural checks, and populates shield-token with a signed token before CF7 sends the AJAX request. This is the exact snippet the plugin adds:
function addShieldFields(form) {
if (form.querySelector('.shield-widget')) return;
var siteKey = (window.vcf7Shield && window.vcf7Shield.siteKey) || '';
if (!siteKey) return;
// Shield widget container — renders here and injects a hidden
// "shield-token" field it populates with a signed token on submit.
var widget = document.createElement('div');
widget.className = 'shield-widget';
widget.setAttribute('data-sitekey', siteKey);
form.appendChild(widget);
if (typeof Shield !== 'undefined') {
Shield.render(widget);
}
// ...also injects a visually-hidden honeypot field
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.wpcf7-form').forEach(addShieldFields);
});
// CF7 re-renders forms after AJAX — re-inject on wpcf7:init
document.addEventListener('wpcf7:init', function (e) {
var root = (e.detail && e.detail.apiResponse) ? e.target : document;
root.querySelectorAll('.wpcf7-form').forEach(addShieldFields);
}); Server phase (on every submission)
When CF7 processes the form, the plugin:
- Blocks immediately if the honeypot field is non-empty.
- Reads the widget-populated
shield-tokenand calls/api/shield/siteverifywith the token, email, and message text. - Blocks if
successisfalse, or if the spam score exceeds your threshold. - If email validation is enabled, checks the email against
/api/scan/emailfor disposable and role addresses. - Otherwise lets CF7 proceed normally and send the email.
// The Shield widget injects and populates a field named "shield-token".
$token = isset( $_POST['shield-token'] )
? sanitize_text_field( wp_unslash( $_POST['shield-token'] ) )
: '';
$result = $this->post_json( '/api/shield/siteverify', [
'secret' => $this->option( 'secret_key' ),
'token' => $token,
'email' => $email,
'text' => $message,
] );
if ( empty( $result['success'] ) ) {
return true; // treated as spam by CF7 — submission blocked
} Fail-open behaviour
If the Verifence API is unreachable (network error, timeout), the plugin fails open — it does not block the submission, so a temporary outage never stops legitimate contact-form traffic.
shield-token is empty. Shield treats an empty token as fail-open and siteverify returns { "success": true, "degraded": true } — the submission is allowed, not blocked, so a genuine visitor with a script blocker still gets through. The honeypot and (if enabled) email validation still run on every submission.
Notes
- Works alongside CF7's own CAPTCHA and Flamingo — it adds to the spam pipeline rather than replacing anything.
- The secret key is stored in
wp_optionsand only ever sent server-to-server over HTTPS. It is never exposed to the browser. - When a submission is blocked, CF7 shows its standard spam-rejection message, which you can customise under CF7's Messages settings.