# Formularios de Framer: cuándo añadir un backend de formularios y cómo

> Los formularios de Framer ya envían a email, Sheets o un webhook; añade Ikiform como webhook para tener envíos guardados y filtrados, avisos al equipo y más destinos.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/website-builder-forms/framer-forms

Los formularios nativos de Framer envían cada envío a email, Google Sheets o un webhook, con protección antispam integrada, así que para una bandeja o una hoja puede que no necesites nada más. Añade Ikiform como destino webhook cuando quieras guardar cada envío con un estado de spam, validarlo contra tus campos, enviarlo por email al equipo y reenviarlo a varios webhooks firmados. Como Framer envía desde sus servidores, o relajas las comprobaciones de origen del formulario o pones en medio un pequeño relay que verifique la firma de Framer.

## Qué cambia en Framer

Framer es el único creador de esta guía sin un límite del que escapar. Sus formularios pueden enviar a email, Google Sheets o cualquier webhook, y Framer tiene protección antispam integrada que marca o bloquea los envíos sospechosos. Sus webhooks están firmados: cada petición lleva una cabecera `Framer-Signature`, un HMAC-SHA256 del cuerpo y del id del envío, y una `Framer-Webhook-Submission-Id`. Framer reintenta hasta cinco veces cuando tu endpoint no responde `2xx`, y no sigue redirecciones.

Así que sé honesto sobre por qué añadirías un backend de formularios. Esto es lo que cubre cada lado:

| Quieres | Solo Framer | Con Ikiform como webhook |
| --- | --- | --- |
| Envíos en una bandeja o una hoja | Sí | Sí, más el panel |
| Un registro consultable con el spam marcado, y exportación CSV | Tu bandeja o tu hoja es el registro | Sí |
| Comprobaciones en el servidor de tipos, longitudes y opciones | No | Sí, con una definición de campos |
| Avisos a varias personas, con Responder dirigido a quien envió | Destino email | Hasta 10 destinatarios, con reply-to |
| Varias herramientas alimentadas desde un formulario, cada una con reintentos | Un webhook por cada destino que añadas | Hasta 3 endpoints firmados, con reintentos y un registro de entregas |
| El mismo backend en sitios de Framer, de Webflow y con código | No | Sí |

Si la primera fila es todo lo que necesitas, quédate con los destinos de Framer. El resto de esta página es para cuando no lo es.

## El problema: Framer envía desde sus servidores

Un destino webhook significa que los servidores de Framer envían el post, no el navegador del visitante. Cambian tres cosas en el lado de Ikiform:

- **Sin origen.** Los envíos desde servidor no llevan cabecera `Origin`, así que con **Allowed domains** configurado, cada envío se trata como si viniera del sitio equivocado.
- **Direcciones IP compartidas.** Ikiform cuenta los límites de frecuencia por dirección IP, y todos los envíos vienen de unas pocas direcciones de Framer en lugar de las de tus visitantes.
- **Sin honeypot.** Framer envía los inputs que creaste y nada más, y su formulario no puede ejecutar la verificación humana de Ikiform.

Puedes aceptarlo, o solucionarlo con un relay. Abajo están los dos caminos.

Diagrama: Un formulario de Framer enviando a Ikiform directamente y a través de un relay firmado

1. Directo: un visitante envía el formulario de Framer, los servidores de Framer lo mandan como JSON sin cabecera Origin, e Ikiform lo acepta con Allowed domains vacío y un límite de frecuencia Relaxed.
2. Relay: los servidores de Framer firman cada envío con tu secreto y lo mandan a un Worker que despliegas tú.
3. El Worker recalcula la firma de Framer. Un envío sin firma válida recibe un 401 y no pasa de ahí.
4. Un envío válido se reenvía a Ikiform con tu clave secreta y el id de envío de Framer como clave de idempotencia, así que un reintento de Framer nunca guarda una segunda copia.

El relay son una docena de líneas de lógica real. A cambio, el formulario puede mantener unos dominios permitidos estrictos, porque solo tu Worker tiene la clave secreta.

## Opción 1: Ikiform como webhook

1. En Framer, dale a cada input un nombre en minúsculas: `name`, `work_email`, `company`, `team_size`. Framer usa los nombres como claves JSON.
2. Selecciona el formulario y, junto a **Send To**, elige **Add…** > **Webhook**. Pega tu endpoint. Deja el secreto vacío; Ikiform no comprueba `Framer-Signature`.
3. En los ajustes del formulario de Ikiform, deja **Allowed domains** vacío, deja **Spam check** desactivado y pon **Rate limit** en **Relaxed**.
4. Publica. Framer solo envía webhooks desde el sitio publicado.

`URL del webhook`:

```text
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx
```

Ikiform responde `201` en cuanto el envío está guardado, lo que Framer cuenta como entregado. Un `422 validation_failed` falla igual en los cinco reintentos, así que arregla los nombres de los inputs en lugar de esperar. La puntuación de spam sigue aplicándose a cada envío: enlaces, frases de spam, direcciones desechables y repeticiones.

## Opción 2: un relay firmado

Despliega un Cloudflare Worker que compruebe la firma de Framer y reenvíe los envíos válidos con tu clave secreta. Así el formulario de Ikiform puede listar tu dominio de Framer en **Allowed domains** con **Reject**, y se rechaza todo lo que no sea un navegador en tu sitio o tu Worker.

`src/index.ts`:

```ts
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 });
  },
};
```

### Despliégalo

`Terminal`:

```bash
npx wrangler secret put FRAMER_SECRET
npx wrangler secret put IKIFORM_SECRET_KEY
npx wrangler deploy
```

- `FRAMER_SECRET` es el secreto que configuras en el destino webhook de Framer. Framer exige al menos 32 caracteres y no volverá a mostrarlo, así que genéralo, guárdalo y pégalo en los dos sitios.
- `IKIFORM_SECRET_KEY` es una API key secreta del panel de Ikiform. Nunca la pongas en Framer.
- La firma es `sha256=` más el HMAC en hex del cuerpo sin procesar seguido del id del envío. Lee el cuerpo una vez como bytes y usa esos mismos bytes para la comprobación y para el reenvío.
- `Idempotency-Key` hace que un reintento de Framer repita la primera respuesta de Ikiform en lugar de guardar un duplicado. Las claves se guardan durante 24 horas.
- El Worker transmite el estado de Ikiform. Framer reintenta cualquier respuesta que no sea `2xx`, hasta cinco veces, así que un `429` o un `5xx` tienen otra oportunidad, mientras que un `422` falla igual cada vez hasta que arreglas los nombres de los inputs.

Después apunta el webhook de Framer a la URL del Worker en lugar de al endpoint, con el secreto rellenado.

> Ahora todos los envíos vienen de tu Worker. Las versiones de servidor envían con una clave secreta, así que Ikiform se salta **Allowed domains** y su verificación humana. Entonces todos los envíos vienen de la IP de tu servidor, y el límite Standard de 5 por minuto por visitante cuenta a todos tus visitantes juntos. Elige el [límite de frecuencia](https://ikiform.com/es/docs/rate-limits.md) Relaxed o Custom para un formulario que envías a través de un servidor, y guarda `IKIFORM_SECRET_KEY` en variables de entorno solo de servidor.

## Opción 3: prescindir del formulario de Framer

Un code component renderiza un formulario real y envía desde el navegador del visitante, así que las comprobaciones de origen, el honeypot y los límites de frecuencia por visitante funcionan como en cualquier sitio. Pierdes la edición visual de formularios de Framer para ese formulario. La [guía de Framer de la documentación](https://ikiform.com/es/docs/guides/framer.md#code-component) tiene el componente.

## Comprueba que funciona en Framer

1. Publica el sitio de Framer y envía el formulario ahí, no en la vista previa del editor.
2. Abre **Submissions** en el panel. El nuevo envío está ahí con todos los campos que enviaste.
3. Comprueba que los nombres de campo coinciden exactamente con los nombres de tus inputs, sin claves añadidas por Framer.
4. Para el relay: envía al Worker una petición con un `Framer-Signature` inventado y confirma que responde `401`.
5. Para el relay: en los detalles del envío, el origen está vacío y el estado es recibido, no spam.
6. Revisa la bandeja de entrada de cada destinatario de las notificaciones. Cada uno recibe un email con los campos, y **Reply** va a quien envió el formulario cuando este tiene un campo `email`.
7. Si añadiste un webhook, abre el endpoint en **Webhooks**. La entrega muestra `succeeded` con la respuesta de tu servidor.

## Errores comunes

| Problema | Qué hacer |
| --- | --- |
| Todos los envíos del webhook están en spam con `origin_mismatch` | **Allowed domains** está configurado mientras Framer envía directamente. Vacíalo, o pon el relay en medio. |
| El Worker responde `401` a los envíos reales | El secreto es distinto entre Framer y el Worker, o algo leyó el cuerpo como texto y lo cambió. Vuelve a pegar el secreto y calcula el hash de los bytes sin procesar. |
| `429 rate_limited` durante un lanzamiento | Todos los envíos comparten las direcciones de Framer o de Cloudflare. Elige **Relaxed**, o un límite Custom. |
| `422 validation_failed` | El envío no coincide con la definición de campos del formulario. `error.fields` indica cada campo y el motivo. Haz que el `name` del input coincida con el id del campo. |
| `403 challenge_required` | La verificación antispam del formulario está en **Ikiform** y un envío con `fetch` no llevaba token. Consigue uno con `challenge(formId)` de `@ikiform/sdk` antes de cada envío, o desactiva la verificación. |

## Preguntas

### ¿Necesito un backend de formularios para los formularios de Framer?

No siempre. Framer envía los envíos a email, Google Sheets o un webhook por sí solo. Añade Ikiform cuando quieras un registro guardado y filtrado, validación en el servidor, avisos al equipo con reply-to o varios webhooks con reintentos desde un formulario.

### ¿Verifica Ikiform la firma del webhook de Framer?

No. Ikiform autentica los envíos por origen o por tu API key secreta, no por la cabecera de Framer. Para comprobar Framer-Signature, pon entre Framer e Ikiform un pequeño relay que la verifique y reenvíe con tu clave secreta.

### ¿Por qué mis envíos de Framer se marcan como spam?

Casi siempre porque Allowed domains está configurado. Los envíos del webhook de Framer vienen de sus servidores sin cabecera Origin, así que no coinciden con ningún dominio. Vacía la lista, o usa un relay que envíe con tu clave secreta.

### ¿Crearán envíos duplicados los reintentos de Framer?

Pueden hacerlo al enviar directamente, si una entrega se reintenta después de que Ikiform la guardara. El relay envía el id de envío de Framer como clave de idempotencia, así que un reintento repite la primera respuesta.

### ¿Puede el formulario aceptar subida de archivos?

Todavía no. Un envío que contiene un archivo se rechaza con 422 files_not_supported. Pide en su lugar un enlace al archivo, como la URL de una carpeta compartida.

## Más guías

- [Más allá de los formularios del creador](https://ikiform.com/es/guides/website-builder-forms.md): Cuando los formularios de Webflow, Netlify, Carrd o Framer chocan con un tope o les falta algo, conserva el formulario que diseñaste y apúntalo a un backend de formularios.
- [Límite de envíos de Webflow](https://ikiform.com/es/guides/website-builder-forms/webflow-submission-limit.md): El plan gratuito Starter de Webflow deja de recoger envíos tras 50 por sitio y los sitios exportados no tienen ninguno, así que apunta el Form Block a Ikiform.
- [Formularios de Carrd](https://ikiform.com/es/guides/website-builder-forms/carrd-forms.md): El formulario de contacto de Carrd solo te avisa por email y los formularios personalizados necesitan Pro Plus, así que usa Send to URL en Plus o un embed HTML en Standard para guardar cada envío.
- [Límite de Netlify Forms](https://ikiform.com/es/guides/website-builder-forms/netlify-forms-limit.md): Los planes antiguos de Netlify miden los envíos de formularios por sitio y te suben de nivel automáticamente, y los planes por créditos pueden pausar el sitio, así que lleva el formulario a un backend.
