Grenzen von Baukasten-Formularen7 Min. Lesezeit
Framer-Formulare: wann ein Formular-Backend sinnvoll ist und wie
Framer-Formulare senden bereits an E-Mail, Sheets oder einen Webhook; ergänze Ikiform als Webhook für gespeicherte, gefilterte Einsendungen, Team-Benachrichtigungen und weitere Ziele.
Die nativen Formulare von Framer senden jede Einsendung an E-Mail, Google Sheets oder einen Webhook, mit eingebautem Spamschutz. Für einen Posteingang oder eine Tabelle brauchst du also vielleicht nichts weiter. Ergänze Ikiform als Webhook-Ziel, wenn du jede Einsendung mit Spam-Status gespeichert, gegen deine Felder validiert, ans Team gemailt und an mehrere signierte Webhooks weitergeleitet haben willst. Da Framer von seinen Servern sendet, lockere entweder die Origin-Prüfungen des Formulars oder setze ein kleines Relay dazwischen, das Framers Signatur prüft.
Was auf Framer anders ist
Framer ist der einzige Builder in dieser Anleitung ohne Limit, dem man entkommen müsste. Seine Formulare können an E-Mail, Google Sheets oder jeden Webhook senden, und Framer hat eingebauten Spamschutz, der verdächtige Einsendungen markiert oder blockiert. Seine Webhooks sind signiert: Jeder Request trägt einen Header Framer-Signature, ein HMAC-SHA256 über Body und Einsendungs-ID, und einen Framer-Webhook-Submission-Id. Framer wiederholt bis zu fünfmal, wenn dein Endpunkt nicht mit 2xx antwortet, und folgt keinen Weiterleitungen.
Sei also ehrlich, warum du ein Formular-Backend ergänzen würdest. Das deckt jede Seite ab:
| Du willst | Nur Framer | Mit Ikiform als Webhook |
|---|---|---|
| Einsendungen in einem Posteingang oder einer Tabelle | Ja | Ja, plus das Dashboard |
| Ein durchsuchbares Archiv mit markiertem Spam und CSV-Export | Dein Posteingang oder deine Tabelle ist das Archiv | Ja |
| Serverseitige Prüfung von Typen, Längen und Optionen | Nein | Ja, mit einer Felddefinition |
| Benachrichtigungen an mehrere Personen, wobei Antworten an den Absender gehen | E-Mail-Ziel | Bis zu 10 Empfänger, mit Reply-to |
| Mehrere Tools aus einem Formular gespeist, jedes mit Wiederholungen | Ein Webhook pro hinzugefügtem Ziel | Bis zu 3 signierte Endpunkte, wiederholt, mit Zustellungsprotokoll |
| Dasselbe Backend für Framer, Webflow und selbst programmierte Sites | Nein | Ja |
Reicht dir die erste Zeile, bleib bei den Zielen von Framer. Der Rest dieser Seite ist für den Fall, dass sie nicht reicht.
Der Haken: Framer sendet von seinen Servern
Ein Webhook-Ziel heißt, dass die Server von Framer den Post senden, nicht der Browser des Besuchers. Auf der Seite von Ikiform ändern sich drei Dinge:
- Kein Origin. Server-Posts tragen keinen
Origin-Header, also wird bei gesetzten Allowed domains jeder Post so behandelt, als käme er von der falschen Site. - Geteilte IP-Adressen. Ikiform zählt Rate-Limits pro IP-Adresse, und jeder Post kommt von wenigen Framer-Adressen statt von denen deiner Besucher.
- Kein Honeypot. Framer sendet die Inputs, die du gebaut hast, und sonst nichts, und sein Formular kann Ikiforms Menschlichkeitsprüfung nicht ausführen.
Du kannst das hinnehmen oder es mit einem Relay beheben. Beide Wege stehen unten.
- Direkt: Ein Besucher sendet das Framer-Formular ab, die Server von Framer senden es als JSON ohne Origin-Header, und Ikiform nimmt es mit leeren Allowed domains und einem Relaxed-Rate-Limit an.
- Relay: Die Server von Framer signieren jeden Post mit deinem Secret und senden ihn an einen Worker, den du deployst.
- Der Worker berechnet die Signatur von Framer neu. Ein Post ohne gültige Signatur bekommt 401 und geht nicht weiter.
- Ein gültiger Post wird mit deinem Secret Key und der Einsendungs-ID von Framer als Idempotency Key an Ikiform weitergeleitet, sodass eine Wiederholung von Framer nie eine zweite Kopie speichert.
Option 1: Ikiform als Webhook
- Gib in Framer jedem Input einen kleingeschriebenen Namen:
name,work_email,company,team_size. Framer nutzt die Namen als JSON-Keys. - Wähle das Formular und neben Send To dann Add… > Webhook. Füge deinen Endpunkt ein. Lass das Secret leer; Ikiform prüft
Framer-Signaturenicht. - Lass in den Einstellungen des Ikiform-Formulars Allowed domains leer, lass Spam check aus und setze Rate limit auf Relaxed.
- Veröffentliche. Framer sendet Webhooks nur von der veröffentlichten Site.
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxxIkiform antwortet mit 201, sobald die Einsendung gespeichert ist, was Framer als zugestellt zählt. Ein 422 validation_failed scheitert bei allen fünf Wiederholungen gleich, also korrigiere die Input-Namen, statt zu warten. Der Spam-Score läuft trotzdem bei jedem Post: Links, Spam-Phrasen, Wegwerfadressen und Wiederholungen.
Option 2: ein signiertes Relay
Deploye einen Cloudflare Worker, der die Signatur von Framer prüft und gültige Posts mit deinem Secret Key weiterleitet. Dann kann das Ikiform-Formular deine Framer-Domain unter Allowed domains mit Reject listen, sodass alles abgewiesen wird, was weder ein Browser auf deiner Site noch dein Worker ist.
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 });
},
};Deployen
npx wrangler secret put FRAMER_SECRET
npx wrangler secret put IKIFORM_SECRET_KEY
npx wrangler deployFRAMER_SECRETist das Secret, das du am Webhook-Ziel von Framer setzt. Framer verlangt mindestens 32 Zeichen und zeigt es nicht erneut an, also erzeuge es, speichere es und füge es an beiden Stellen ein.IKIFORM_SECRET_KEYist ein geheimer API-Key aus dem Ikiform-Dashboard. Leg ihn nie in Framer ab.- Die Signatur ist
sha256=plus das Hex-HMAC über den rohen Body, gefolgt von der Einsendungs-ID. Lies den Body einmal als Bytes und nutze genau diese Bytes für die Prüfung und die Weiterleitung. Idempotency-Keysorgt dafür, dass eine Wiederholung von Framer die erste Antwort von Ikiform wiedergibt, statt ein Duplikat zu speichern. Keys werden 24 Stunden aufbewahrt.- Der Worker reicht den Status von Ikiform durch. Framer wiederholt jede Antwort außerhalb von
2xxbis zu fünfmal, also bekommt ein429oder5xxeine weitere Chance, während ein422jedes Mal gleich scheitert, bis du die Input-Namen korrigierst.
Richte den Webhook von Framer dann auf die URL des Workers statt auf den Endpunkt, mit eingetragenem Secret.
IKIFORM_SECRET_KEY in Umgebungsvariablen, die nur der Server sieht.Option 3: das Formular von Framer weglassen
Eine Code-Komponente rendert ein echtes Formular und sendet aus dem Browser des Besuchers, sodass Origin-Prüfungen, der Honeypot und Rate-Limits pro Besucher wie auf jeder Site funktionieren. Du verlierst für dieses Formular die visuelle Formularbearbeitung von Framer. Die Framer-Anleitung der Doku enthält die Komponente.
Prüfen, dass es auf Framer funktioniert
- Veröffentliche die Framer-Site und sende das Formular dort ab, nicht in der Vorschau des Editors.
- Öffne Submissions im Dashboard. Die neue Einsendung ist da, mit jedem Feld, das du gesendet hast.
- Prüfe, dass die Feldnamen genau zu deinen Input-Namen passen, ohne von Framer ergänzte Keys.
- Für das Relay: Sende einen Request mit einer erfundenen
Framer-Signaturean den Worker und prüfe, dass er mit401antwortet. - Für das Relay: In den Details der Einsendung ist der Origin leer und der Status received, nicht spam.
- Prüfe das Postfach jedes Benachrichtigungsempfängers. Jeder bekommt eine E-Mail mit den Feldern, und Reply geht an den Absender, wenn das Formular ein
email-Feld hat. - Wenn du einen Webhook hinzugefügt hast, öffne den Endpunkt unter Webhooks. Die Zustellung zeigt
succeededmit der Antwort deines Servers.
Stolperfallen
| Problem | Was zu tun ist |
|---|---|
Jeder Webhook-Post liegt mit origin_mismatch im Spam | Allowed domains ist gesetzt, während Framer direkt sendet. Leere die Liste oder setze das Relay dazwischen. |
Der Worker antwortet auf echte Posts mit 401 | Das Secret unterscheidet sich zwischen Framer und Worker, oder etwas hat den Body als Text gelesen und verändert. Füge das Secret erneut ein und hashe die rohen Bytes. |
429 rate_limited während eines Launches | Alle Posts teilen sich die Adressen von Framer oder Cloudflare. Wähle Relaxed oder ein Custom-Limit. |
422 validation_failed | Der Post passt nicht zur Felddefinition des Formulars. error.fields nennt jedes Feld und den Grund. Gleiche den name des Eingabefelds an die Feld-ID an. |
403 challenge_required | Die Spamprüfung des Formulars steht auf Ikiform, und ein fetch-Post hatte kein Token. Hol dir vor jedem Absenden eins mit challenge(formId) aus @ikiform/sdk oder schalte die Prüfung aus. |
Fragen
Nicht immer. Framer sendet Einsendungen selbst an E-Mail, Google Sheets oder einen Webhook. Ergänze Ikiform, wenn du ein gespeichertes, gefiltertes Archiv, serverseitige Validierung, Team-Benachrichtigungen mit Reply-to oder mehrere wiederholte Webhooks aus einem Formular willst.
Nein. Ikiform authentifiziert Posts über den Origin oder deinen geheimen API-Key, nicht über den Header von Framer. Um Framer-Signature zu prüfen, setze ein kleines Relay zwischen Framer und Ikiform, das sie verifiziert und mit deinem Secret Key weiterleitet.
Meist, weil Allowed domains gesetzt ist. Die Webhook-Posts von Framer kommen von seinen Servern ohne Origin-Header, passen also zu keiner Domain. Leere die Liste oder nutze ein Relay, das mit deinem Secret Key sendet.
Beim direkten Senden schon, wenn eine Zustellung wiederholt wird, nachdem Ikiform sie gespeichert hat. Das Relay sendet die Einsendungs-ID von Framer als Idempotency Key, sodass eine Wiederholung stattdessen die erste Antwort wiedergibt.
Noch nicht. Ein Post mit einer Datei wird mit 422 files_not_supported abgelehnt. Bitte stattdessen um einen Link zur Datei, etwa die URL eines geteilten Laufwerks.
Hängst du bei einem Schritt fest oder willst eine Anleitung für deinen Fall? Schreib an hello@ikiform.com.