BrunoP.Blog

How to prevent form spam without CAPTCHA (Honeypot and Time-trap)

reCAPTCHA stops bots, but kills conversion and annoys real users. Learn how to protect your forms using the Honeypot and Time-trap methods, with clean, copy-pasteable code for your site.

Nobody likes solving visual puzzles to submit a simple contact form. Traditional reCAPTCHA (and similar alternatives) add friction at the most critical moment of your funnel: user conversion. Studies show that complex CAPTCHA challenges can drop lead conversion rates by up to 3% to 5%.

The smart alternative is invisible security. Instead of forcing a human to prove they are not a robot, we make the robot reveal its identity silently. Two classic and highly effective techniques for this are the Honeypot and the Time-trap.

How the Honeypot Method Works

Automated spam bots crawl the web by parsing raw HTML code. When they find a <form> tag, they attempt to fill out every available text field to maximize the chance of their message getting through, completely ignoring visual styles.

A Honeypot is an extra form field that is completely hidden from human eyes using CSS, but remains visible in the raw code to bots. If the form is submitted and this hidden field contains any data, we know with absolute certainty that it was filled by a script, and we reject the request.

Pro tip: Do not use obvious names like honeypot, spam, or hidden_field in the name attribute. Advanced bots avoid these. Use realistic names that mimic regular inputs, like website, phone_extension, or address_line2, and set tabindex="-1" so keyboard-navigating users do not tab into it.

How the Time-trap Method Works

Robots are built to fill and submit forms as fast as possible, often within fractions of a second. Real humans take time to read the page, focus the inputs, type their name, email, and compose a message — a process that rarely takes less than 3 to 5 seconds.

A Time-trap logs the exact timestamp when the form page loaded (usually saved in a PHP session or encrypted inside a token). When the data hits the server, we check if the time elapsed is below our safety threshold (e.g., 3 seconds). If it was submitted too fast, the submission is blocked.

Crucial Warning: Treat as the FIRST LAYER

While Honeypots and Time-traps block roughly 95% of generic automated scripts, they are not a complete security solution. Sophisticated bots running on headless browsers (like Puppeteer or Playwright) can execute JS, detect hidden fields, and inject artificial delays before submitting.

Therefore, you must pair these techniques with robust backend practices:

  • Server-Side Validation & Sanitization: Never rely on browser email validation. Validate formats in PHP and sanitize inputs.
  • Escape All Output: If you output form data anywhere (like error logs or admin dashboards), filter strings with htmlspecialchars() to prevent XSS (Cross-Site Scripting). Never echo raw input.
  • Rate Limiting: Prevent an attacker from abusing your mail server by restricting the maximum submissions allowed per IP address per minute.

Try both techniques live in the interactive simulator below.

Simulator: Honeypot & Time-trap

Honeypot Field Vazio / Empty
Time-trap 0.00s
PHP backend console

[Sistema] Servidor pronto para validação local.

[Sistema] Aguardando envio em modo Humano...

Código Pronto: Cole no seu site

<!-- Formulário HTML -->
<form action="processa.php" method="POST">
  <!-- Campo de time-trap dinâmico (carregado via PHP) -->
  <input type="hidden" name="form_token" value="<?= time(); ?>">

  <div class="campo-grupo">
    <label for="nome">Nome</label>
    <input type="text" id="nome" name="nome" required>
  </div>

  <div class="campo-grupo">
    <label for="email">E-mail</label>
    <input type="email" id="email" name="email" required>
  </div>

  <!-- CAMPO HONEYPOT (Oculto via CSS de forma orgânica) -->
  <div class="campo-oculto-protecao">
    <label for="website">Website</label>
    <input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
  </div>

  <div class="campo-grupo">
    <label for="mensagem">Mensagem</label>
    <textarea id="mensagem" name="mensagem" required></textarea>
  </div>

  <button type="submit">Enviar</button>
</form>

<style>
/* Esconde o Honeypot sem usar "display: none" */
.campo-oculto-protecao {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
  opacity: 0;
  pointer-events: none;
}
</style>
<?php
/**
 * processa.php - Validação de segurança no Backend
 */
session_start();

// 1. Validação de Time-trap (Mínimo de 3 segundos para digitação)
$tempo_minimo = 3;
$token_carregamento = filter_input(INPUT_POST, 'form_token', FILTER_VALIDATE_INT);

if (!$token_carregamento || (time() - $token_carregamento) < $tempo_minimo) {
    // Rejeita a submissão rápida demais
    http_response_code(400);
    exit("Erro: Envio bloqueado por validação de tempo.");
}

// 2. Validação de Honeypot (O campo oculto "website" deve estar vazio)
$honeypot = filter_input(INPUT_POST, 'website', FILTER_DEFAULT);

if (!empty($honeypot)) {
    // Rejeita se o bot preencheu o campo invisível
    http_response_code(400);
    exit("Erro: Spam detectado.");
}

// 3. Sanitização e Validação do restante dos inputs
$nome = filter_input(INPUT_POST, 'nome', FILTER_DEFAULT);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$mensagem = filter_input(INPUT_POST, 'mensagem', FILTER_DEFAULT);

if (!$email) {
    http_response_code(400);
    exit("Erro: E-mail inválido.");
}

// 4. PRIMEIRA CAMADA CONCLUÍDA - Preparação segura dos dados
// Escapa toda e qualquer saída em tela ou relatórios para prevenir XSS
$nome_seguro = htmlspecialchars($nome ?? '', ENT_QUOTES, 'UTF-8');
$mensagem_segura = htmlspecialchars($mensagem ?? '', ENT_QUOTES, 'UTF-8');

// IMPORTANTE: Combine esta camada com validações server-side robustas,
// verificação de CSRF tokens e regras de rate limiting por IP para 
// blindar totalmente o processamento de envios contra ataques distribuídos.

echo "Sucesso! Mensagem de " . $nome_seguro . " processada de forma segura.";

Quero blindar a segurança dos meus formulários e site

FAQ

Do Honeypot and Time-trap block all spam? No. They filter out most generic automated spam bots. More advanced bots (running headless browsers) require server-side defenses, IP validation, and rate limiting. The methods described here are the first layer of defense.
Does hiding the Honeypot with display: none work? Some smarter bots ignore fields marked with display: none. The best strategy is to hide the input using absolute negative positioning or opacity zero.
How do I ensure PHP doesn't execute malicious code? Always filter incoming variables (e.g. via filter_input) and use htmlspecialchars() on all outputs. Never echo raw user input.

This guide is part of the Website security series. References: OWASP — Anti-Spam, MDN — HTML Inputs.