Stopping monitoring submissions reaching your team
A form check proves your form still sends leads by sending one. That enquiry is real: it goes wherever your enquiries go. This page is how to make sure it goes nowhere near a person, without the check losing its meaning.
What this buys you
Two things. Nobody on your team ever sees a monitoring enquiry, because it never becomes one - your handler answers normally and stores nothing. And the frequency ceiling lifts: a check whose submissions reach a person is held to once a day on purpose, because twenty-four synthetic leads a day is a decision about somebody's working morning rather than a monitoring setting. A check that reaches nobody can run as often as your plan allows.
What arrives, if you change nothing
Every check submits as the same made-up person, and keeps the same values for as long as the check exists. All four are things a CRM rule can match on.
- From
- monitor-<id>@checks.senriko.com
- On
- +1 201 555 01NN
- Tagged
- utm_source=senriko-monitor
- Messages beginning
- [SENRIKO TEST <id> - DO NOT CONTACT]
The header we send
Every request a check makes carries a header naming the workspace it belongs to. Nothing else sends it, and nobody else can guess it.
X-Senriko-Monitor: your-workspace-token
Your token is in the form check wizard, beside the box that declares this is set up. Treat it as a secret: anything that knows it can make a request your site will discard.
What to do with it
- Read the X-Senriko-Monitor header on the incoming request.
- Compare it to your workspace token, with a constant-time comparison if your language offers one.
- If it matches, skip everything the submission would normally trigger - no CRM record, no notification, no email to your sales team.
- Answer exactly as you would have. Same status code, same redirect, same thank-you page.
That last step is the one that matters. The check reads what a visitor would see, so a handler that discards the submission and then returns an error will be reported as a broken form - correctly, because that is what a visitor would get.
Is this a hole in your form?
It is a header, so anybody could send it - which is exactly why it must only ever make you do less, never more. Discarding a submission is safe. Skipping validation, skipping a captcha, returning a different status code, or trusting any other field because the header is present would not be. If your handler branches on it to do anything except stop early, take the branch out.
The token, and whether you need it
The header carries a token unique to your workspace, so you can check that a request naming us is actually ours. Checking it is optional: the worst an impostor achieves by sending the header is to have their own submission discarded. Check it if your handler does anything beyond discarding, and check it as a constant-time comparison rather than with ==.
Why we take your word for it
We cannot see inside your backend, so this is a declaration rather than something we verify - and the interface says so where you make it. What we do verify is that the form still behaves normally with our header on the request: the trial run has to pass with the header present, so a backend that rejects unfamiliar headers outright fails at setup rather than silently every hour afterwards.
The same four steps, in code
Whichever of these your site is built on, the shape is identical: read the header, compare it in constant time, skip the side effects, and answer exactly as you would have.
`SENRIKO_TOKEN` is your workspace token, from the form check wizard. Keep it in your environment, not in the file - anything that knows it can make a request your site will discard.
PHP
$sent = $_SERVER['HTTP_X_SENRIKO_MONITOR'] ?? '';
if (hash_equals(getenv('SENRIKO_TOKEN'), $sent)) {
// Answer exactly as you would have, and do nothing else.
header('Location: /thank-you', true, 303);
exit;
}Node.js / Express
import { timingSafeEqual } from 'node:crypto';
function isMonitor(req) {
const sent = Buffer.from(req.get('x-senriko-monitor') ?? '');
const token = Buffer.from(process.env.SENRIKO_TOKEN ?? '');
// Lengths first: timingSafeEqual throws when they differ, which would
// turn a short header into a 500 for anybody who sends one.
return sent.length === token.length && timingSafeEqual(sent, token);
}
app.post('/contact', (req, res) => {
if (isMonitor(req)) return res.redirect(303, '/thank-you');
// ... your normal handling
});Python / Django
import hmac, os
def is_monitor(request):
sent = request.headers.get('X-Senriko-Monitor', '')
return hmac.compare_digest(sent, os.environ.get('SENRIKO_TOKEN', ''))
def contact(request):
if is_monitor(request):
return redirect('/thank-you')
# ... your normal handlingRuby on Rails
def monitor?
sent = request.headers['X-Senriko-Monitor'].to_s
ActiveSupport::SecurityUtils.secure_compare(sent, ENV.fetch('SENRIKO_TOKEN', ''))
end
def create
return redirect_to('/thank-you', status: :see_other) if monitor?
# ... your normal handling
endWordPress
// Runs before the form plugin sends anything. The hook name differs by
// plugin - this one is Contact Form 7; WPForms uses wpforms_process.
add_action('wpcf7_before_send_mail', function ($form) {
$sent = $_SERVER['HTTP_X_SENRIKO_MONITOR'] ?? '';
if (hash_equals(getenv('SENRIKO_TOKEN'), $sent)) {
$form->skip_mail = true;
}
});On something else? Any framework that can read a request header can do this. The only part worth care is the comparison: use your language's constant-time equality rather than ==, and handle a header of the wrong length without erroring.
What this does and does not prove
With the submission discarded, the check still proves the page loads, the form can be filled in and submitted, the server accepts it, and your conversion signals fire. It stops proving that a lead reaches your CRM, because you have asked us not to send one. If that last step is what you need watched, leave the submissions arriving and filter them in your CRM instead.
What it does not change
The check still opens your page, still fills the form in, still presses the button, and still watches for the conversion signal - so everything above the server's answer is proved exactly as before. What changes is only where the submission ends up. And the Proof Level says so: with the submission discarded by you rather than delivered, the CRM-delivery rung stays unconfirmed, because nothing arrived to confirm it.