Formulário de contato em site estático7 min de leitura
Adicione um formulário de contato na Netlify sem o Netlify Forms
Rode um formulário de contato num site da Netlify sem o Netlify Forms: sem detecção no build, envios JSON a partir do React e um formulário separado para deploy previews.
Deixe o data-netlify fora do formulário e aponte o action dele para o seu endpoint do Ikiform; assim a Netlify serve a página e nunca mexe no envio. Formulários em React e Vue não precisam de uma cópia HTML oculta e podem enviar JSON. Defina um id de formulário diferente para os deploy previews no netlify.toml, porque os hosts de preview não correspondem ao seu site em Allowed domains.
O que muda na Netlify
A Netlify é o único grande host estático com um recurso de formulários embutido. O Netlify Forms lê o HTML publicado depois de cada build, encontra os formulários marcados com data-netlify ou netlify e aceita envios para o seu próprio site nesses formulários. Todo outro envio para uma página estática falha, e na Netlify ele falha com 404, não 405:
curl -i -X POST -d "message=hello" https://your-site.netlify.app/contact/HTTP/2 404
server: Netlify
cache-status: "Netlify Edge"; fwd=method; fwd-status=404
content-length: 0Esse 404 faz as pessoas caçarem uma página faltando que não está faltando. Ele significa que nenhum formulário detectado correspondeu ao envio. Usar ou não o Netlify Forms é outra questão, e a comparação entre Ikiform e Netlify Forms responde com honestidade: se o seu site vai ficar para sempre na Netlify e o formulário é HTML simples, o Netlify Forms dá menos trabalho. Esta página é para os outros casos.
| Sua situação | Por que o Netlify Forms atrapalha |
|---|---|
| O formulário é renderizado por React, Vue ou Svelte | O build analisa HTML estático, então um formulário renderizado no cliente precisa de uma cópia oculta para a Netlify encontrar |
Você quer enviar JSON com fetch | O Netlify Forms só aceita corpos urlencoded e multipart |
| O site pode mudar de host | O formulário envia para o seu próprio domínio, então só funciona enquanto a Netlify servir esse domínio |
| As mensagens devem chegar a um webhook que você verifica | O Ikiform assina cada entrega com headers do Standard Webhooks e tenta de novo quando falha |
- Com o Netlify Forms, a Netlify analisa o HTML de cada deploy em busca de formulários marcados com data-netlify.
- Um formulário encontrado aceita envios para o seu próprio site, e a Netlify os armazena.
- Um formulário não encontrado, como um renderizado por JavaScript sem cópia oculta, recebe 404 em todo envio.
- Com o Ikiform, nada precisa ser encontrado no build.
- O formulário envia direto para ikiform.com, como HTML ou JSON, e o Ikiform armazena e manda um e-mail para você.
Tire um formulário do Netlify Forms
- Remova
data-netlifyounetlify,netlify-honeypotedata-netlify-recaptchado formulário, e qualquer input ocultoform-name. Se ficar, oform-nameé armazenado como um campo comum. - Apague a cópia estática oculta de um formulário JavaScript, como a de baixo. A Netlify só precisava dela para detectar o formulário.
- Defina o
action, ou a URL dofetch, como o seu endpoint do Ikiform. O antigoaction="/thanks"vai para a configuração Redirect after submit do formulário. - Baixe antes os envios antigos na página Forms da Netlify. Eles não migram sozinhos.
<form name="contact" netlify hidden>
<input name="name" />
<input name="email" />
<textarea name="message"></textarea>
</form>Deixe o form detection ligado se outros formulários do site ainda usam o Netlify Forms. A documentação da Netlify diz que desligar a detecção é só para sites que não usam o Netlify Forms. Quando nada mais o usar, desligá-lo economiza uma análise a cada deploy.
O que substitui as configurações de spam da Netlify
A Netlify roda o Akismet nos envios e oferece netlify-honeypot e reCAPTCHA. No Ikiform, o honeypot continua funcionando se você definir o Honeypot field do formulário com o nome que já usa, como bot-field. A pontuação de spam roda em todo envio sem configuração, e o Spam check definido como Ikiform troca o reCAPTCHA pelo Cloudflare Turnstile, sem chaves. Remova a div do reCAPTCHA quando fizer a troca.
Um formulário React que envia JSON
Sem o Netlify Forms no caminho, um formulário renderizado no cliente não precisa de cópia e pode enviar JSON, o que mantém os tipos intactos e permite limpar os valores antes. Este também registra qual contexto da Netlify gerou a página:
import { type FormEvent, useState } from "react";
const ENDPOINT = `https://ikiform.com/f/${import.meta.env.VITE_IKIFORM_FORM_ID}`;
interface Message {
name: string;
email: string;
message: string;
context: string;
}
export function ContactForm() {
const [sent, setSent] = useState(false);
const [error, setError] = useState("");
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const body: Message & Record<string, string> = {
name: String(data.get("name") ?? "").trim(),
email: String(data.get("email") ?? "").trim(),
message: String(data.get("message") ?? "").trim(),
context: import.meta.env.VITE_CONTEXT ?? "local",
_gotcha: String(data.get("_gotcha") ?? ""),
};
setError("");
const response = await fetch(ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(body),
}).catch(() => null);
const result = await response?.json().catch(() => null);
if (result?.ok) return setSent(true);
const fields: Record<string, string[]> = result?.error?.fields ?? {};
setError(Object.values(fields)[0]?.[0] ?? result?.error?.message ?? "Couldn't send. Try again.");
}
if (sent) return <p role="status">Got it. I'll answer from my own inbox, usually the same day.</p>;
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">Name</label>
<input id="name" name="name" autoComplete="name" required />
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" autoComplete="email" required />
<label htmlFor="message">Message</label>
<textarea id="message" name="message" rows={6} minLength={10} required />
<input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
{error ? <p role="alert">{error}</p> : null}
<button>Send</button>
</form>
);
}Content-Type: application/jsondiz ao Ikiform para interpretar JSON;Accept: application/jsonpede uma resposta em JSON.VITE_CONTEXTé um nome de exemplo. A Netlify defineCONTEXTdurante o build; exponha-a ao Vite no seu comando de build, ou remova o campo.- O honeypot é enviado como uma chave JSON. Mantenha-o no corpo mesmo com o input oculto, para que os bots que o preenchem continuem se denunciando.
Os deploy previews ganham um formulário próprio
Os deploy previews ficam em hosts como deploy-preview-12--your-site.netlify.app. Isso não é um subdomínio de your-site.netlify.app, então não corresponde em Allowed domains, e os envios de preview caem no spam. Dê aos previews e aos branch deploys um formulário próprio no netlify.toml, e defina o header Content-Security-Policy no mesmo arquivo:
[build]
command = "npm run build"
publish = "dist"
[context.production.environment]
VITE_IKIFORM_FORM_ID = "frm_xxxxxxxxxxxxxxxx"
[context.deploy-preview.environment]
VITE_IKIFORM_FORM_ID = "frm_yyyyyyyyyyyyyyyy"
[context.branch-deploy.environment]
VITE_IKIFORM_FORM_ID = "frm_yyyyyyyyyyyyyyyy"
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"Deixe Allowed domains do formulário de preview vazio, ou adicione o host de preview exato enquanto testa. O formulário de produção fica com o seu domínio e your-site.netlify.app. Os headers no netlify.toml valem para todos os contextos de deploy; se você preferir um arquivo _headers, ele precisa acabar no diretório de publicação.
netlify.app sozinho em Allowed domains. Todo site da Netlify passaria a corresponder, inclusive cópias do seu formulário em sites de outras pessoas.Confira se funciona
- Abra um deploy preview, envie e confirme que a mensagem cai no formulário de preview.
- Faça o merge e envie em produção. Confirme que a mensagem cai no formulário de produção e que a página Forms da Netlify não mostra nada novo.
- Confira a caixa de entrada de cada destinatário das notificações. Cada um recebe um e-mail com os campos, e Reply vai para quem enviou quando o formulário tem um campo
email. - Envie com o honeypot preenchido,
_gotcha=bot. Ele ainda recebe uma resposta de sucesso, mas o envio é armazenado como spam e não dispara e-mail nem webhook. - Não chegou nada? Mude o filtro de status do painel para Spam. Spam recebe a mesma resposta de sucesso de um envio real.
Pegadinhas
| Problema | O que fazer |
|---|---|
404 ao enviar | O envio foi para o seu próprio site. Um build em cache pode ainda ter o action antigo, ou uma chamada fetch ainda envia para /. Procure form-name no diretório de publicação. |
| Os envios ainda aparecem na Netlify | Algum formulário da página ainda envia para o seu próprio site com data-netlify ou netlify, então a Netlify continua detectando e armazenando. Remova o atributo, defina o action como o Ikiform e faça o deploy de novo. |
404 not_found do Ikiform só nos previews | O contexto de deploy preview não tem VITE_IKIFORM_FORM_ID, então a URL termina em undefined. Adicione-a em [context.deploy-preview.environment]. |
403 origin_not_allowed, ou todo envio cai no spam | O domínio da página não está em Allowed domains do formulário. Adicione-o, mais localhost para testes locais. Subdomínios de um domínio listado são permitidos. |
422 files_not_supported | O formulário tem um <input type="file"> com um arquivo escolhido. Upload de arquivos ainda não é suportado; remova o input ou peça um link. |
Perguntas
Sim. A Netlify só trata os formulários que detectou no build. Um formulário sem data-netlify cujo action aponta para outro endpoint é servido pela Netlify como qualquer página e envia direto para esse endpoint.
A Netlify responde a um POST para uma página estática com 404, a menos que o Netlify Forms tenha detectado aquele formulário no HTML publicado. Marque o formulário para o Netlify Forms ou aponte o action dele para outro backend.
Sim. A detecção é por formulário, pelo atributo. Mantenha data-netlify nos formulários que a Netlify deve tratar e deixe o form detection ligado.
Eles ficam na Netlify, não no Ikiform. Baixe-os na página Forms do site antes de desligar o form detection, e guarde o arquivo com os seus registros.
Ainda não. Um envio que contém um arquivo é recusado com 422 files_not_supported. Peça um link para o arquivo, como a URL de um drive compartilhado.
Travou em algum passo ou quer um guia para o seu caso? Envie um e-mail para hello@ikiform.com.