Stop spam bots on any website form. No captcha, no cloud service, no API key.
Most spam bots post forms directly and never run JavaScript. local-antispam ships ct_checkjs: a tiny script that sets a cookie of the same name in real browsers, plus a one-line check in your form handler that rejects requests without it. Nothing leaves your server.
With a bundler:
npm install local-antispamimport 'local-antispam';Or with a script tag, in <head> and without defer, so the cookie is set before the visitor can submit the form:
<script src="https://cdn.jsdelivr.net/npm/local-antispam@1/dist/ct_checkjs.js"></script>To serve it yourself, copy node_modules/local-antispam/dist/ct_checkjs.js to your public directory.
Node.js / TypeScript (Express):
function ctValidateCheckjs(cookieHeader: string = ''): boolean {
const match = /(?:^|;\s*)ct_checkjs=(\d{4})(?:;|$)/.exec(cookieHeader);
return match !== null && Math.abs(Number(match[1]) - new Date().getFullYear()) <= 1;
}
app.post('/contact', (req, res) => {
if (!ctValidateCheckjs(req.headers.cookie)) {
return res.status(403).send('Bot');
}
// Process the form.
});PHP:
function ct_validate_checkjs($value)
{
return is_string($value) && ctype_digit($value) && abs((int) $value - (int) date('Y')) <= 1;
}
if (!ct_validate_checkjs($_COOKIE['ct_checkjs'] ?? null)) {
http_response_code(403);
exit('Bot');
}Snippets for Node.js, PHP, Python, Go, Ruby, Java, C#, Kotlin, Rust and Perl are in BACKENDS.md.
- The
ct_checkjsscript stores the current year in thect_checkjscookie. - The browser sends the cookie with the form.
- Your backend accepts the current year, or one year either side to allow for time zones and wrong device clocks.
The check has to run on your backend: a script in the browser cannot stop a bot that posts directly to your form handler.
- It only catches bots that do not run JavaScript. Bots driving a real browser, and bots written to send this cookie, get through.
- Visitors with JavaScript or cookies turned off are rejected, so tell them why on your error page.
CleanTalk Anti-Spam checks every submission in the cloud, against IP and email reputation and message content.