Vá além dos formulários do criador8 min de leitura
Formulários do Framer: quando adicionar um backend de formulários, e como
Os formulários do Framer já enviam para e-mail, Sheets ou um webhook; adicione o Ikiform como webhook para envios armazenados e filtrados, alertas à equipe e mais destinos.
Os formulários nativos do Framer enviam cada resposta para e-mail, Google Sheets ou um webhook, com proteção contra spam embutida, então para uma caixa de entrada ou uma planilha talvez você não precise de mais nada. Adicione o Ikiform como destino de webhook quando quiser cada envio armazenado com status de spam, validado contra os seus campos, enviado por e-mail à equipe e encaminhado para vários webhooks assinados. Como o Framer envia a partir dos servidores dele, afrouxe as verificações de origem do formulário ou coloque no meio um pequeno relay que verifica a assinatura do Framer.
O que muda no Framer
O Framer é o único criador deste guia sem um limite do qual escapar. Os formulários dele podem enviar para e-mail, Google Sheets ou qualquer webhook, e o Framer tem proteção contra spam embutida que marca ou bloqueia envios suspeitos. Os webhooks dele são assinados: cada requisição traz um header Framer-Signature, um HMAC-SHA256 do corpo e do id do envio, e um Framer-Webhook-Submission-Id. O Framer tenta de novo até cinco vezes quando o seu endpoint não responde 2xx, e não segue redirecionamentos.
Então seja honesto sobre por que você adicionaria um backend de formulários. Veja o que cada lado cobre:
| Você quer | Só o Framer | Com o Ikiform como webhook |
|---|---|---|
| Envios numa caixa de entrada ou numa planilha | Sim | Sim, mais o painel |
| Um registro pesquisável com spam marcado, e exportação CSV | Sua caixa de entrada ou planilha é o registro | Sim |
| Verificações no servidor de tipos, tamanhos e opções | Não | Sim, com uma definição de campos |
| Alertas para várias pessoas, com a resposta indo para quem enviou | Destino de e-mail | Até 10 destinatários, com reply-to |
| Várias ferramentas alimentadas por um formulário, cada uma com novas tentativas | Um webhook por destino que você adiciona | Até 3 endpoints assinados, com novas tentativas e log de entregas |
| O mesmo backend no Framer, no Webflow e em sites feitos com código | Não | Sim |
Se a primeira linha é tudo de que você precisa, fique com os destinos do Framer. O resto desta página é para quando não é.
O porém: o Framer envia a partir dos servidores dele
Um destino de webhook significa que os servidores do Framer enviam o post, não o navegador do visitante. Três coisas mudam do lado do Ikiform:
- Sem origem. Envios de servidor não trazem header
Origin, então com Allowed domains configurado, todo envio é tratado como vindo do site errado. - Endereços IP compartilhados. O Ikiform conta os limites de taxa por endereço IP, e todo envio vem de alguns poucos endereços do Framer em vez dos endereços dos seus visitantes.
- Sem honeypot. O Framer envia os inputs que você montou e nada mais, e o formulário dele não consegue rodar a verificação humana do Ikiform.
Você pode aceitar isso, ou resolver com um relay. Os dois caminhos estão abaixo.
- Direto: um visitante envia o formulário do Framer, os servidores do Framer o mandam como JSON sem header Origin, e o Ikiform aceita com Allowed domains vazio e um limite de taxa Relaxed.
- Relay: os servidores do Framer assinam cada envio com o seu segredo e o mandam para um Worker que você publica.
- O Worker recalcula a assinatura do Framer. Um envio sem assinatura válida recebe 401 e não vai adiante.
- Um envio válido é encaminhado ao Ikiform com a sua chave secreta e com o id de envio do Framer como chave de idempotência, então uma nova tentativa do Framer nunca armazena uma segunda cópia.
Opção 1: o Ikiform como webhook
- No Framer, dê a cada input um nome em minúsculas:
name,work_email,company,team_size. O Framer usa os nomes como chaves do JSON. - Selecione o formulário e, ao lado de Send To, escolha Add… > Webhook. Cole o seu endpoint. Deixe o segredo vazio; o Ikiform não confere
Framer-Signature. - Nas configurações do formulário no Ikiform, deixe Allowed domains vazio, deixe o Spam check desligado e defina Rate limit como Relaxed.
- Publique. O Framer só envia webhooks a partir do site publicado.
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxxO Ikiform responde 201 assim que o envio é armazenado, o que o Framer conta como entregue. Um 422 validation_failed falha do mesmo jeito nas cinco tentativas, então corrija os nomes dos inputs em vez de esperar. A pontuação de spam continua rodando em todo envio: links, frases de spam, endereços descartáveis e repetições.
Opção 2: um relay assinado
Publique um Cloudflare Worker que confere a assinatura do Framer e encaminha os envios válidos com a sua chave secreta. Aí o formulário do Ikiform pode listar o seu domínio do Framer em Allowed domains com Reject, e tudo que não for um navegador no seu site ou o seu Worker é recusado.
interface Env {
FRAMER_SECRET: string;
IKIFORM_SECRET_KEY: string;
}
const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";
const encoder = new TextEncoder();
async function signatureFor(secret: string, body: ArrayBuffer, submissionId: string) {
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const id = encoder.encode(submissionId);
const message = new Uint8Array(body.byteLength + id.byteLength);
message.set(new Uint8Array(body), 0);
message.set(id, body.byteLength);
const digest = new Uint8Array(await crypto.subtle.sign("HMAC", key, message));
return `sha256=${[...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
}
function sameText(a: string, b: string) {
const left = encoder.encode(a);
const right = encoder.encode(b);
return left.byteLength === right.byteLength && crypto.subtle.timingSafeEqual(left, right);
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method !== "POST") return new Response(null, { status: 405 });
const signature = request.headers.get("framer-signature") ?? "";
const submissionId = request.headers.get("framer-webhook-submission-id") ?? "";
const body = await request.arrayBuffer();
if (!submissionId || !sameText(signature, await signatureFor(env.FRAMER_SECRET, body, submissionId))) {
return new Response("Bad signature", { status: 401 });
}
const response = await fetch(ENDPOINT, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${env.IKIFORM_SECRET_KEY}`,
"Idempotency-Key": submissionId,
},
body,
});
if (response.ok) return new Response(null, { status: 204 });
return new Response(await response.text(), { status: response.status });
},
};Publique
npx wrangler secret put FRAMER_SECRET
npx wrangler secret put IKIFORM_SECRET_KEY
npx wrangler deployFRAMER_SECRETé o segredo que você define no destino de webhook do Framer. O Framer exige pelo menos 32 caracteres e não o mostra de novo, então gere, guarde e cole nos dois lugares.IKIFORM_SECRET_KEYé uma chave de API secreta do painel do Ikiform. Nunca a coloque no Framer.- A assinatura é
sha256=mais o HMAC em hex do corpo bruto seguido do id do envio. Leia o corpo uma vez como bytes e use esses mesmos bytes na verificação e no encaminhamento. Idempotency-Keyfaz uma nova tentativa do Framer repetir a primeira resposta do Ikiform em vez de armazenar um duplicado. As chaves ficam guardadas por 24 horas.- O Worker repassa o status do Ikiform. O Framer tenta de novo qualquer resposta que não seja
2xx, até cinco vezes, então um429ou5xxganha outra chance, enquanto um422falha do mesmo jeito toda vez até você corrigir os nomes dos inputs.
Depois aponte o webhook do Framer para a URL do Worker em vez do endpoint, com o segredo preenchido.
IKIFORM_SECRET_KEY em variáveis de ambiente só do servidor.Opção 3: dispense o formulário do Framer
Um code component renderiza um formulário de verdade e envia a partir do navegador do visitante, então verificações de origem, o honeypot e os limites de taxa por visitante funcionam como em qualquer site. Você perde a edição visual de formulários do Framer para esse formulário. O guia do Framer na documentação traz o componente.
Confira se funciona no Framer
- Publique o site do Framer e envie o formulário lá, não no preview do editor.
- Abra Submissions no painel. O novo envio está lá com todos os campos que você enviou.
- Confira se os nomes dos campos batem exatamente com os nomes dos inputs, sem chaves adicionadas pelo Framer.
- Para o relay: envie uma requisição ao Worker com um
Framer-Signatureinventado e confirme que ele responde401. - Para o relay: nos detalhes do envio, a origem está vazia e o status é recebido, não spam.
- 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. - Se você adicionou um webhook, abra o endpoint em Webhooks. A entrega mostra
succeededcom a resposta do seu servidor.
Pegadinhas
| Problema | O que fazer |
|---|---|
Todo envio de webhook cai em spam com origin_mismatch | Allowed domains está configurado enquanto o Framer envia direto. Limpe, ou coloque o relay no meio. |
O Worker responde 401 para envios reais | O segredo é diferente entre o Framer e o Worker, ou algo leu o corpo como texto e o alterou. Cole o segredo de novo e calcule o hash dos bytes brutos. |
429 rate_limited durante um lançamento | Todos os envios compartilham os endereços do Framer ou da Cloudflare. Escolha Relaxed, ou um limite Custom. |
422 validation_failed | O envio não corresponde à definição de campos do formulário. error.fields aponta cada campo e o motivo. Faça o name do input bater com o id do campo. |
403 challenge_required | A verificação de spam do formulário está como Ikiform e um envio por fetch não tinha token. Obtenha um com challenge(formId) de @ikiform/sdk antes de cada envio, ou desligue a verificação. |
Perguntas
Nem sempre. O Framer envia as respostas para e-mail, Google Sheets ou um webhook sozinho. Adicione o Ikiform quando quiser um registro armazenado e filtrado, validação no servidor, alertas à equipe com reply-to ou vários webhooks com novas tentativas a partir de um formulário.
Não. O Ikiform autentica envios pela origem ou pela sua chave de API secreta, não pelo header do Framer. Para conferir o Framer-Signature, coloque entre o Framer e o Ikiform um pequeno relay que o verifica e encaminha com a sua chave secreta.
Na maioria das vezes porque Allowed domains está configurado. Os envios de webhook do Framer vêm dos servidores dele sem header Origin, então não batem com nenhum domínio. Limpe a lista ou use um relay que envia com a sua chave secreta.
Podem, ao enviar direto, se uma entrega for tentada de novo depois que o Ikiform a armazenou. O relay manda o id de envio do Framer como chave de idempotência, então uma nova tentativa repete a primeira resposta.
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.