🇧🇷 Português · 🇺🇸 English
Verificação humana open source, leve e focada em privacidade, que protege sites e aplicativos contra spam e bots.
💙 Projeto aberto a contribuições. Veja como ajudar ou procure issues marcadas com
good first issue.
O Humnovo é um projeto open source de verificação humana criado para proteger sites e aplicações contra bots, spam e atividades automatizadas maliciosas.
A proposta é oferecer uma camada moderna, leve, segura e acessível de autenticação humana, fácil de integrar a qualquer plataforma por meio de bibliotecas, APIs e componentes reutilizáveis.
Com foco em privacidade, simplicidade e flexibilidade, o Humnovo ajuda aplicações a distinguir usuários reais de automações, priorizando uma experiência fluida para usuários e desenvolvedores.
- 🛡️ Proteção contra bots: bloqueia spam e automações maliciosas
- 🔒 Privacidade em primeiro lugar: sem rastreamento invasivo de usuários
- ⚡ Leve: impacto mínimo no carregamento e na performance
- ♿ Acessível: navegável por teclado e compatível com leitores de tela
- 🧩 Fácil integração: bibliotecas, API REST e componentes reutilizáveis
- 🎯 Um clique: verificação fluida e não intrusiva
- 🔧 Flexível: configurável para diferentes níveis de segurança
- 🌐 Open source: transparente, auditável e mantido pela comunidade
- O widget do Humnovo é carregado na página.
- A verificação ocorre de forma leve e não intrusiva.
- Um token de verificação é gerado.
- O backend da sua aplicação valida o token junto à API do Humnovo (uso único).
O Humnovo é self-hosted: você roda um servidor minúsculo (zero dependências, só Node.js 18+) e qualquer site, em qualquer linguagem, passa a usá-lo.
1. Gere as chaves
npx humnovo keys
# HUMNOVO_SITE_KEY=hn_pk_...
# HUMNOVO_SECRET_KEY=hn_sk_...2. Suba o servidor (escolha um)
# Node.js
HUMNOVO_SITE_KEY=hn_pk_... HUMNOVO_SECRET_KEY=hn_sk_... HUMNOVO_HOSTNAMES=meusite.com.br npx humnovo
# Docker
docker build -t humnovo https://github.com/psflow/humnovo.git
docker run -p 8787:8787 -e HUMNOVO_SITE_KEY=hn_pk_... -e HUMNOVO_SECRET_KEY=hn_sk_... humnovoOu em um clique no Render (as chaves são geradas automaticamente; em produção, defina HUMNOVO_DEMO=0 e HUMNOVO_HOSTNAMES):
Quer só experimentar? Rode
npx humnovosem nada e abra http://localhost:8787: há uma página demo com chaves temporárias.
3. Coloque o widget no formulário e valide o token no backend (veja abaixo).
<form action="/enviar" method="POST">
<input type="email" name="email" placeholder="Seu e-mail" />
<div class="humnovo" data-sitekey="SUA_CHAVE_PUBLICA"></div>
<button type="submit">Enviar</button>
</form>
<script src="https://humnovo.seusite.com/widget.js" async defer></script>O widget adiciona ao formulário um campo oculto humnovo-token. A URL da API é descoberta a partir do src do script (ou use data-api).
| Atributo | Descrição |
|---|---|
data-sitekey |
Chave pública (obrigatório) |
data-theme |
auto (padrão), light ou dark |
data-lang |
auto (padrão), pt-BR, en, es |
data-api |
URL do servidor Humnovo |
data-callback |
Nome de função global chamada com o token |
data-error-callback |
Função global chamada em caso de erro |
data-expired-callback |
Função global chamada quando o token expira |
data-input-name |
Nome do campo oculto (padrão humnovo-token) |
Também são disparados os eventos DOM humnovo:success, humnovo:error e humnovo:expired.
import { Humnovo } from 'humnovo';
const humnovo = new Humnovo({
siteKey: 'SUA_CHAVE_PUBLICA',
apiUrl: 'https://humnovo.seusite.com',
container: '#humnovo-container',
onSuccess: (token) => console.log('Verificação concluída:', token),
onError: (error) => console.error('Falha na verificação:', error.code),
});
humnovo.render();
// humnovo.getToken(), humnovo.reset(), humnovo.destroy()const response = await fetch('https://humnovo.seusite.com/v1/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: process.env.HUMNOVO_SECRET_KEY,
token: req.body['humnovo-token'],
}),
});
const result = await response.json();
if (result.success) {
// Usuário humano verificado
} else {
// Bloquear requisição
}Exemplos prontos em examples/: HTML puro, Express e PHP.
import express from 'express';
import { createHumnovo } from 'humnovo/server';
const humnovo = createHumnovo({
sites: [{ siteKey: process.env.HUMNOVO_SITE_KEY, secret: process.env.HUMNOVO_SECRET_KEY, hostnames: ['meusite.com.br'] }],
});
app.use('/humnovo', humnovo); // serve /humnovo/widget.js e a API
app.post('/contato', express.urlencoded({ extended: false }), async (req, res) => {
const result = await humnovo.verify(req.body['humnovo-token']);
if (!result.success) return res.status(400).send('Verificação falhou');
// ...
});Funciona também com node:http puro: http.createServer(createHumnovo({...})).
- Desafio de prova de trabalho (PoW): o servidor envia um
salte um hashSHA-256(salt + n); o navegador precisa descobrirn. O desafio é assinado com HMAC, então o servidor não guarda estado. - Resolução em segundo plano: começa assim que o usuário passa o mouse/foca no widget, roda num Web Worker e leva frações de segundo. Para quem automatiza em escala, o custo de CPU se acumula.
- Sinais de interação leves: clique confiável (
isTrusted), tempo desde o carregamento, movimento de ponteiro, teclado ou toque enavigator.webdriver. São apenas contadores e booleanos: sem cookies, fingerprint ou dados pessoais. - Token de uso único: assinado, com expiração curta (5 min) e preso ao hostname. Seu backend valida uma única vez.
⚠️ Nenhuma solução bloqueia 100% dos bots. O Humnovo aumenta o custo da automação; para alvos críticos, combine com rate limiting. Veja o modelo de ameaça.
Peso: widget de ~19 KB (~7 KB gzip), sem dependências, com estilos isolados em Shadow DOM.
Acessibilidade: navegável por teclado, role="checkbox" com estados ARIA, mensagens em aria-live e respeito a prefers-reduced-motion.
Retorna um desafio assinado (usado pelo widget).
Recebe a solução e os sinais e devolve { success, token, expiresIn } (usado pelo widget).
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
secret |
string |
Sim | Chave secreta da aplicação |
token |
string |
Sim | Token gerado pelo widget |
Aceita JSON ou application/x-www-form-urlencoded.
Resposta:
{
"success": true,
"timestamp": "2026-11-08T14:50:00.000Z",
"hostname": "seusite.com",
"siteKey": "hn_pk_..."
}Em caso de falha: { "success": false, "error": "token-expired" }. Códigos possíveis: invalid-input, invalid-token, invalid-secret, token-expired, token-reused.
GET /widget.js: o widget para<script>GET /health: verificação de saúde
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
siteKey |
string |
— | Chave pública do site |
container |
string |
— | Seletor ou elemento onde será exibido |
apiUrl |
string |
origem do script | URL do servidor Humnovo |
theme |
string |
'auto' |
'light', 'dark' ou 'auto' |
language |
string |
'auto' |
'auto', 'pt-BR', 'en', 'es' |
inputName |
string |
'humnovo-token' |
Nome do campo oculto do formulário |
onSuccess |
function |
— | Callback ao concluir a verificação |
onError |
function |
— | Callback em caso de erro |
onExpire |
function |
— | Callback quando o token expira |
Via variáveis de ambiente (PORT, HOST, HUMNOVO_SITE_KEY, HUMNOVO_SECRET_KEY, HUMNOVO_HOSTNAMES, HUMNOVO_LEVEL) ou um humnovo.config.json com vários sites (veja humnovo.config.example.json):
| Opção do site | Padrão | Descrição |
|---|---|---|
siteKey |
— | Chave pública |
secret |
— | Chave secreta (mín. 16 caracteres) |
hostnames |
qualquer | Domínios permitidos; aceita curinga *.meusite.com |
level |
medium |
low (só PoW leve), medium ou high (PoW maior e sinais mais rigorosos) |
maxNumber |
pelo nível | Dificuldade do PoW (média de hashes = maxNumber / 2) |
Para várias instâncias atrás de um load balancer, passe um store compartilhado (ex.: Redis) para createHumnovo({ store }): qualquer objeto com consume(key, expiresAt) → boolean.
| Site | Onde | Integração |
|---|---|---|
| PS Smart Solutions | Formulário de contato | Site estático em Next.js com envio pelo Formspree; o widget libera o envio após a verificação |
Usa o Humnovo no seu site ou app? Abra um PR adicionando uma linha nesta tabela.
- Widget JavaScript base
- API REST de verificação
- Opção de self-hosting (Node.js, Docker e Render)
- Componentes para React, Vue e Angular
- SDKs para Python, PHP e Java
- Store Redis oficial e rate limiting embutido
- Modo invisível
- Painel de administração
- Plugins para WordPress e outras plataformas
- Mais idiomas
npm test # testes (node:test, sem dependências)
npm start # servidor local em modo demo
npm run build # gera dist/humnovo.jsContribuições são muito bem-vindas!
- Faça um fork do projeto
- Crie uma branch para sua feature:
git checkout -b feature/minha-feature - Faça commit das alterações:
git commit -m 'feat: adiciona minha feature' - Envie para o repositório:
git push origin feature/minha-feature - Abra um Pull Request
Antes de contribuir, leia o CONTRIBUTING.md e o Código de Conduta.
O Humnovo é gratuito e open source. Se ele ajuda o seu site ou aplicativo, considere apoiar pelo GitHub Sponsors.
O apoio financia tempo de desenvolvimento para novas funcionalidades (componentes React/Vue, plugin WordPress, modo invisível), manutenção, documentação e revisões de segurança.
Não pode apoiar financeiramente? Dar uma ⭐ no repositório, compartilhar o projeto ou abrir uma issue com feedback também ajuda muito.
Encontrou uma vulnerabilidade? Não abra uma issue pública. Consulte o SECURITY.md para reportá-la de forma responsável.
Distribuído sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.
Pedro Silva
- GitHub: @psflow
- LinkedIn: workerpedro
Feito com 💙 para uma web mais humana.



