← Alle Guides
Vercel

Kontaktformular auf Vercel ohne Backend

Kontaktformular für deine Seite auf Vercel, ohne eigene Function: ein HTML-Formular oder fetch(), E-Mail-Benachrichtigung, Spamschutz ohne Captcha.

Vercel liefert deine Seite aus und führt Functions aus, die du selbst schreibst, sammelt aber keine Formular-Einsendungen für dich. Ein <form> auf einer Vercel-Seite braucht einen Endpoint, der den POST annimmt, die Nachricht speichert und sie dir mailt. Den kannst du als Vercel Function selbst schreiben, oder du richtest das Formular auf ein gehostetes Formular-Backend und deployst nichts zusätzlich. Bei Formlane ist dieser Endpoint https://smallwerk.com/formlane/api/submit. Das funktioniert gleich für reines HTML, Astro, Hugo, Vite/React, SvelteKit oder Next.js auf Vercel: keine API-Route, kein Secret in den Umgebungsvariablen, keine Änderung an vercel.json. Einsendungen werden in Frankfurt gespeichert und an die Adresse deines Kontos gemailt, mit Reply-To auf den Absender.

So geht's

  1. Melde dich bei Formlane an, leg ein Formular an und kopiere den Access Key (fl_…).
  2. Füg das Formular unten in deine Kontaktseite ein und ersetze fl_YOUR_ACCESS_KEY durch deinen Key. Der Key ist absichtlich öffentlich (mit ihm kann man nur an dieses eine Formular senden), er darf also im HTML oder im Client-Code stehen.
  3. Setz das versteckte Feld redirect auf eine Danke-Seite auf deiner eigenen Domain, z. B. https://example.com/thanks.
  4. Beschränke das Formular in den Einstellungen auf deine Produktions-Domain, damit Formulare auf anderen Websites nicht daran senden können.
  5. Push in dein Git-Repository (oder führ vercel aus), öffne die veröffentlichte Seite, schick eine Testnachricht und prüf dein Postfach und das Formlane-Dashboard.

Code

contact.html
<form action="https://smallwerk.com/formlane/api/submit" method="POST">
  <input type="hidden" name="access_key" value="fl_YOUR_ACCESS_KEY">
  <input type="hidden" name="subject" value="New message from my Vercel site">
  <input type="hidden" name="redirect" value="https://example.com/thanks">

  <!-- Honeypot: hidden from people, leave it unchecked -->
  <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" autocomplete="off">

  <label for="name">Name</label>
  <input id="name" type="text" name="name" required>

  <label for="email">Email</label>
  <input id="email" type="email" name="email" required>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <button type="submit">Send</button>
</form>

Funktioniert als Kontaktseite jedes Frameworks, das du auf Vercel deployst. Das Feld email wird zur Reply-To-Adresse der Benachrichtigung, du antwortest also mit einem Klick. Die Beschriftungen im Snippet (Name, Email, Message, Send) sind englisch; für eine deutsche Seite ersetzt du sie, die name-Attribute bleiben.

Optional: auf der Seite bleiben

Lieber eine Bestätigung ohne Seitenwechsel? Schick dasselbe Formular per fetch(). message in der Antwort ist immer englisch, deshalb zeigt das Snippet je nach error-Code einen eigenen Text. Die Texte im Snippet sind englisch; ersetz sie für eine deutsche Seite:

contact.html (vor </body>)
<script>
  const MESSAGES = {
    limit_reached: "This form can't take more messages this month. Please email us directly.",
    rate_limited: "Too many messages in a short time. Please try again in a few minutes.",
    origin_not_allowed: "This form only accepts messages from its own website.",
  };
  const form = document.querySelector('form[action*="formlane"]');
  if (form) form.addEventListener("submit", async (event) => {
    event.preventDefault();
    // FormData skips the unchecked honeypot checkbox, so real visitors never send it.
    const data = Object.fromEntries(new FormData(form));
    try {
      const res = await fetch(form.action, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify(data),
      });
      const json = await res.json();
      form.outerHTML = json.success
        ? "<p>Thanks! Your message has been sent.</p>"
        : "<p>" + (MESSAGES[json.error] || "Sorry, that didn't work. Please try again later.") + "</p>";
    } catch {
      alert("Network error. Please try again.");
    }
  });
</script>

Du nutzt React, Vite oder Next.js? Der React-Guide hat eine fertige Komponente, der Next.js-Guide zeigt dasselbe ohne API-Route.

So sieht die Antwort aus

Mit Accept: application/json antwortet Formlane mit JSON:

  • Erfolg (HTTP 200): {"success": true, "message": "Form submitted successfully", "id": "…"}
  • Fehler (4xx/5xx): {"success": false, "message": "…", "error": "…"}. Fehlercodes sind unter anderem invalid_key, origin_not_allowed, rate_limited und limit_reached.

Ein reines HTML-Formular (ohne Accept: application/json) wird nach einer erfolgreichen Einsendung auf deine redirect-URL weitergeleitet.

Grenzen: 64 KB pro Einsendung, 50 Felder, 10.000 Zeichen pro Feld, 10 Einsendungen in 10 Minuten pro Besucher und Formular. Datei-Uploads gehen noch nicht.

Hinweise für Vercel

  • Keine Function in deinem Projekt: Das Formular sendet direkt aus dem Browser des Besuchers an Formlane. Du deployst keine Function, setzt kein Secret, und dein Vercel-Projekt hat für das Formular keine Function-Nutzung.
  • Preview-Deployments: Erlaubte Domains gelten für die Domain und ihre Subdomains. Vercel-Preview-URLs (zum Beispiel my-site-git-feature-my-team.vercel.app) sind keine Subdomains deiner Produktionsadresse, ein Eintrag deckt sie also nicht ab. Teste auf deiner Produktions-Domain oder trag den genauen Preview-Hostnamen kurz ein. Trag nie vercel.app allein ein: Dann wären Einsendungen von jeder Seite auf vercel.app erlaubt.
  • Eigene Domain: Setz das Feld redirect auf deine eigene Domain, nicht auf die *.vercel.app-Adresse, damit Besucher bei deiner Marke bleiben.
  • Erlaubte Domains sind eine Browser-Prüfung. Sie verhindern, dass Formulare auf anderen Websites deinen Key nutzen. Ein Skript, das den Origin-Header fälscht, kommt trotzdem durch; Honeypot, Rate-Limit und Inhaltsregeln greifen dann weiterhin.

Andere Wege (ehrlicher Vergleich)

WegGut fürWorauf du achten musst
Gehostetes Formular-Backend (Formlane, Formspree, Web3Forms und andere)Kontakt- und Anfrageformulare auf jeder Seite bei Vercel; kein Code zum DeployenMonatliche Kontingente; jeder Dienst hat einen eigenen Free-Plan und eigene Funktionen (Datei-Uploads, Webhooks, Autoresponder unterscheiden sich)
Eigene Vercel Function oder Next.js Server Action + eine E-Mail-APIVolle Kontrolle, eigene Logik, Daten bleiben in deinem StackValidierung, Spamschutz, Rate-Limit, Speicherung und E-Mail-Versand baust und pflegst du selbst
E-Mail aus dem Browser (z. B. EmailJS)Eine E-Mail mit Vorlage direkt aus dem Client-Code sendenNachrichten sind E-Mails, keine gespeicherte Liste; prüf, wie Spam behandelt wird
Netlify FormsSeiten, die auf Netlify laufenFunktioniert nur für Seiten auf Netlify, nicht auf Vercel

Formlane passt, wenn du ein reines HTML-Formular auf Vercel willst, Einsendungen in Frankfurt gespeichert werden sollen und du Spamschutz ohne Captcha brauchst. Brauchst du heute Datei-Uploads, Autoresponder, Webhooks oder ein Captcha, nimm einen Dienst, der das schon kann: Formlane kann es noch nicht.

Preise

Free: 250 Einsendungen im Monat und bis zu 5 Formulare. Starter: 9 € im Monat für 2.500 Einsendungen. Pro: 19 € im Monat für 25.000 Einsendungen. Preise inkl. MwSt.

Häufige Fragen

Hat Vercel eine eingebaute Formularverarbeitung?

Vercel hostet deine Seite und führt Functions aus, die du schreibst, sammelt aber keine Formular-Einsendungen für dich. Entweder schreibst du eine Function, die den POST annimmt, oder du richtest die action des Formulars auf ein Formular-Backend wie Formlane.

Brauche ich eine API-Route oder Vercel Function für ein Kontaktformular?

Nicht mit einem Formular-Backend. Das Formular sendet direkt an https://smallwerk.com/formlane/api/submit; dort wird die Nachricht gespeichert und an dich gemailt. Auf Vercel wird nichts zusätzlich deployt.

Darf der Access Key im HTML stehen?

Ja. Der Formlane-Access-Key ist absichtlich öffentlich und erlaubt nur Einsendungen an genau dieses Formular. Beschränke das Formular in den Einstellungen auf deine Domain, damit Formulare auf anderen Websites ihn nicht nutzen können.

Funktioniert das mit Next.js, Astro, SvelteKit oder reinem HTML auf Vercel?

Ja. Das Formular ist reines HTML (oder ein fetch()-Aufruf) und funktioniert deshalb mit jedem Framework, das Vercel hostet, auch bei einem komplett statischen Projekt.

Wie wird Spam gefiltert?

Mit einer versteckten Honeypot-Checkbox, einem Rate-Limit pro Besucher und einfachen Inhaltsregeln (zum Beispiel gegen Link-Fluten), ohne Captcha. Details im Guide Kontaktformular-Spam stoppen ohne Captcha.

Wo werden die Einsendungen gespeichert?

Einsendungen werden in Frankfurt gespeichert, in einer Supabase-Datenbank (Region eu-central-1). Die App läuft bei Vercel, Benachrichtigungen gehen über einen E-Mail-Dienstleister; alle Dienstleister stehen in der Datenschutzerklärung.

Was passiert beim Monatslimit?

Neue Einsendungen werden mit dem Fehler limit_reached abgelehnt, bis der nächste Kalendermonat beginnt oder du upgradest. Gespeicherte Einsendungen bleiben.

Access Key holen

Kostenlos für 250 Einsendungen pro Monat. Einsendungen werden in Frankfurt gespeichert.

Access Key holen