[ ENGINEERING_GUIDE ][ RECAPTCHA ][ SICHERHEIT ][ FORMULARE ][ NEXTJS ]

reCAPTCHA v3 — unsichtbarer Spam-Schutz für Formulare (Komplettguide 2026)

10. Juni 202611 Min. Lesezeit
Autor: DevStudio.itWeb & KI Studio

Client-Token, API-Route-Verifizierung, Score-Schwelle 0,5, lazyOnload in layout.tsx, DSGVO-Hinweis und Honeypot/Rate-Limit — Next.js-Produktionsmuster.

READ_TIME: 11 MIN_COMPLEXITY: MED_
STAMP: VERIFIED_BY_DS_

Kurzfassung

reCAPTCHA v3 zeigt keine „Ich bin kein Roboter“-Checkbox — es liefert einen Score von 0,0–1,0 und ein kurzlebiges Token, das Sie serverseitig per siteverify prüfen müssen, bevor ein Lead gespeichert oder eine E-Mail versendet wird. Auf einer produktiven Next.js-15-Unternehmensseite lädt das Skript per lazyOnload in layout.tsx (LCP-Schutz), und das Kontaktformular wartet auf grecaptcha.ready mit 12 s Timeout — sonst bleibt das Token oft leer und die API antwortet mit 400. Schwelle 0,5 ist ein sinnvoller Start; dazu IP-Rate-Limit (5 Anfragen/Minute in diesem Projekt), optional Honeypot und dasselbe Muster für den Chatbot. Im Folgenden: Ablauf, DSGVO, False Positives und Tests.

Für wen ist das

  • Dienstleister mit Kontaktformular oder Chatbot für Lead-Generierung
  • Next.js / React-Entwickler, die Schutz ohne nerviges v2-Captcha wollen
  • Verantwortliche für DSGVO / Datenschutz — Hinweis am Formular und Datenübermittlung an Google
  • Teams mit Spam im Postfach trotz „irgendeinem Captcha“ im WordPress-Theme — auf der Suche nach serverseitigem Muster

Keyword (SEO)

recaptcha v3 kontaktformular, formular spam schutz, recaptcha nextjs api route, recaptcha score schwelle, recaptcha server verifizierung, lazyOnload recaptcha layout, dsgvo recaptcha google

Warum v3 statt v2-Checkbox

Google reCAPTCHA entwickelte sich von sichtbaren Rätseln zu unsichtbarer Risikobewertung. Bei v3 klickt der Nutzer meist nichts — das Skript wertet Signale aus (Domain-Historie, Bewegungsmuster, Fingerprint) und liefert einen Score. Das ist besseres UX auf B2B-Seiten, wo „Wählen Sie alle Ampeln“ die Conversion killt.

Aspekt reCAPTCHA v2 (Checkbox) reCAPTCHA v3
UX Sichtbare Aufgabe Unsichtbar; Badge in der Ecke
Ergebnis bestanden / nicht Score 0,0–1,0
Entscheidung vor allem in Google-UI Sie serverseitig (Schwelle)
Performance Schwerer iframe Leichter, trotzdem externes Skript

v3 ersetzt nicht Feldvalidierung, Rate Limits oder Plausibilitätschecks — es ist eine Schicht in Defence in Depth.

Architektur auf Next.js 15 (Produktionsmuster)

Im Software-House-Projekt (mehrsprachig /pl, /en, /de) sitzt der Schutz an drei Stellen: globales Skript im Layout, execute() beim Submit, Verifizierung in /api/submissions.

Skript in layout.tsxlazyOnload

Das reCAPTCHA-Tag lädt nicht afterInteractive wie GA4 — bewusst lazyOnload, damit es nicht mit Analytics um den First Paint konkurriert und LCP nicht leidet. Der Site Key ist öffentlich und steht in der URL:

<Script
  src="https://www.google.com/recaptcha/api.js?render=6Lcwsx0sAAAAAO4sbP31qTdgjuoGLgMmp9HyxhYB"
  strategy="lazyOnload"
/>

Der Code-Kommentar ist eindeutig: Skript ist lazy — das Formular muss auf ready warten, sonst entsteht kein Token.

Badge und Rechtstext — zwei Ebenen

Google verlangt ein sichtbares reCAPTCHA-Badge. Im Layout schneidet CSS das Badge auf ein kleines Icon unten links zu (overflow hidden), der vollständige Rechtstext steht am Kontaktformular in page.tsx — mit Links zu Google-Datenschutz und Nutzungsbedingungen (Übersetzungen in messages/pl.json, en.json, de.json):

{translations.contact.form.recaptchaBeforePrivacy}
<a href="https://policies.google.com/privacy">...</a>
{translations.contact.form.recaptchaBetween}
<a href="https://policies.google.com/terms">...</a>
{translations.contact.form.recaptchaAfter}

Das ist wichtig für die DSGVO: Nutzer wissen, dass Daten zur Anti-Spam-Analyse an Google LLC gehen können — ein verstecktes Badge allein reicht nicht.

Clientseitig — Token beim Formular-Submit

In handleSubmit des Kontaktformulars execute() nicht blind bei onClick aufrufen — bei lazyOnload ist window.grecaptcha die ersten Sekunden oft undefined.

Muster: auf ready warten, dann execute

await new Promise((resolve, reject) => {
  const t = setTimeout(() => reject(new Error('recaptcha_timeout')), 12000);
  const done = () => { clearTimeout(t); resolve(); };
  if (window.grecaptcha?.ready) {
    window.grecaptcha.ready(done);
  } else {
    const iv = setInterval(() => {
      if (window.grecaptcha?.ready) {
        clearInterval(iv);
        window.grecaptcha.ready(done);
      }
    }, 100);
    setTimeout(() => {
      clearInterval(iv);
      if (!window.grecaptcha?.ready) reject(new Error('recaptcha_no_script'));
    }, 12000);
  }
});

const recaptchaToken = await window.grecaptcha.execute(
  '6Lcwsx0sAAAAAO4sbP31qTdgjuoGLgMmp9HyxhYB',
  { action: 'submit_contact_form' }
);

Die Action (submit_contact_form) erscheint in der reCAPTCHA-Konsole und in Logs — separate Actions für den Chatbot (submit_chatbot_form) erleichtern die Score-Analyse pro Kanal.

Token im POST-Body zusammen mit Lead-Feldern senden:

const response = await fetch('/api/submissions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ...data, locale, recaptchaToken }),
});

Schlägt execute fehl, klare Meldung anzeigen („Bitte kurz warten nach dem Laden…“) — kein leeres Token erzwingen.

TypeScript-Typen für grecaptcha in src/types/gtag.d.ts neben gtag pflegen.

Serverseitig — Verifizierung in der API-Route

Secret Key niemals in den Browser. In Vercel / .env RECAPTCHA_SECRET_KEY setzen und in POST /api/submissions aufrufen:

const recaptchaResponse = await fetch(
  'https://www.google.com/recaptcha/api/siteverify',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `secret=${recaptchaSecret}&response=${recaptchaToken}`,
  }
);
const recaptchaData = await recaptchaResponse.json();

Entscheidungsreihenfolge in Produktion:

  1. Kein Token → HTTP 400 (Bots überspringen oft JS).
  2. success: false (z. B. timeout-or-duplicate, falscher Secret) → 400 + Log error-codes.
  3. score < 0.5 → 400 (Bot / verdächtiger Traffic).
  4. Erst dann Feldvalidierung und Prisma-Speicherung + Transaktions-Mails.
if (recaptchaData.score !== undefined && recaptchaData.score < 0.5) {
  return NextResponse.json(
    { error: 'Verifizierung fehlgeschlagen. Seite neu laden und erneut versuchen.' },
    { status: 400 }
  );
}

Token ist Einmalnutzung und kurzlebig — nicht zwischen Requests cachen. Bei Netzwerkfehlern zu Google Submission blockieren (fail closed); ein offener Endpoint ohne Prüfung lädt Spammer ein.

Score-Schwelle — 0,5, 0,7 oder „weich“

Google behandelt den Score als Signal, nicht als Absolutwert. In der Praxis:

Schwelle Effekt Wann
0,3 Weniger False Positives, mehr Spam Sehr wenig Traffic, A/B-Tests
0,5 Balance (Default in vielen Guides) Unternehmensseiten, B2B-Leads
0,7 Aggressiver Filter Formulare mit Anreiz (E-Book, Gutschein)

In diesem Projekt Start bei 0,5. Nach einer Woche reCAPTCHA Admin → Analytics für Action submit_contact_form prüfen. Liegen 5 % legitimer Leads bei 0,45–0,49, eher 0,45 oder zusätzliches Rate Limit statt harter 0,7.

Weiche Schwelle: Score 0,3–0,5 → Queue „manuelle Prüfung“ statt harter Ablehnung — sinnvoll bei Ads-Traffic von neuen Geräten (VPN, Safari ITP).

Rate Limit — erste Verteidigungslinie (bereits im Projekt)

Bevor Google ins Spiel kommt, ruft /api/submissions checkEmailRateLimit(ip) aus src/lib/email-rate-limit.ts auf:

  • 5 Anfragen pro IP pro 60 Sekunden
  • bei Überschreitung: HTTP 429 + Header Retry-After

Schützt vor einfachen Skripten und Floods, die E-Mail-Kontingente leeren würden. Derselbe Helper schützt weitere Mail-Endpoints (Chatbot, Verträge, Testimonials).

Rate Limit ersetzt nicht reCAPTCHA — Botnetze mit vielen IPs kommen durch. Zusammen erhöhen sie Angriffskosten.

Honeypot — wann eine dritte Schicht

In diesem Repo noch kein Honeypot-Feld — OK bei v3 + Rate Limit bei moderatem Traffic. Honeypot ergänzen, wenn:

  • wiederholter Spam mit akzeptablem Score (Bot-Farmen),
  • einfaches HTML-Formular leicht scrapbar,
  • null Kosten gewünscht (verstecktes Feld website, company_url — CSS position:absolute; left:-9999px, tabIndex={-1}, autoComplete="off").

Server lehnt ab, wenn Honeypot nicht leer — ohne „Sie sind ein Bot“ (weniger Feedback für Angreifer). Reihenfolge: Rate Limit → Honeypot → reCAPTCHA → fachliche Validierung.

Chatbot — gleiches Muster, eigener Endpoint

Das Kontaktformular nutzt /api/submissions mit voller reCAPTCHA-Prüfung. Der Chatbot-Endpoint /api/chatbot/submit hat derzeit Rate Limit, aber keine Token-Prüfung — typische Lücke, sobald Spammer die JSON-API finden.

Empfohlener Plan (passend zur Architektur):

  1. verifyRecaptchaToken(token, minScore) nach src/lib/recaptcha.ts auslagern.
  2. In der Chatbot-Komponente — derselbe ready + execute-Block mit Action submit_chatbot_form.
  3. In POST /api/chatbot/submit — identische Verifizierung wie bei submissions.
  4. reCAPTCHA-Hinweis beim letzten Chatbot-Schritt (Kurzfassung des Formulartexts).

Ein Site Key, ein Secret, zwei Actions in der Google-Konsole — einfacheres Debugging als zwei reCAPTCHA-Projekte.

DSGVO, Cookies und Datenschutzerklärung

reCAPTCHA v3 verarbeitet Nutzerdaten bei Google (USA — Transfermechanismen: SCC, DPF je nach aktuellem Rechtsstand). Mindest-Paket Compliance:

  • Hinweis am Formular (Google Privacy + Terms) — bereits in der UI.
  • In der Datenschutzerklärung: Zweck (Anti-Spam), Datenkategorien (IP, Google-Cookies, Verhaltenssignale), Rechtsgrundlage (berechtigtes Interesse Art. 6 Abs. 1 lit. f oder Einwilligung — Anwalt bei Marketing-Cookies).
  • Blockiert ein Cookie-Banner Google-Skripte bis zur Einwilligung — reCAPTCHA läuft ggf. nicht; entweder Kategorie „notwendig“ für Anti-Spam oder Laden nach Consent mit klarer Formular-Meldung.
  • Aufbewahrung: Score-Logs in der API kurz halten; reCAPTCHA-Tokens nicht dauerhaft in der Lead-Tabelle speichern.

v3 ist nicht „cookie-frei“ — Badge und Google-Doku sagen das Gegenteil.

False Positives — was tun

Nutzer mit VPN, Tor, frischen Browser-Profilen, Adblockern gegen google.com/recaptcha oder Firmen-Proxy bekommen manchmal niedrige Scores trotz echter Anfrage.

Symptome in Logs:

  • recaptcha_no_script / recaptcha_timeout clientseitig,
  • score too low mit 0,1–0,4 bei sinnvoller Projektbeschreibung,
  • „Formular geht nicht“ nur unter Firefox mit ETP.

Gegenmaßnahmen:

  1. Meldung mit Aufforderung zum Reload / direkte E-Mail (kontakt@...).
  2. Schwelle temporär senken + Monitoring.
  3. Fallback: Telefon oder Calendly neben dem Formular.
  4. Schutz nicht komplett abschalten zugunsten nur Honeypot — gezielter Spam bleibt.

Von der Produktionsdomain testen — localhost muss in der reCAPTCHA-Domainliste stehen, sonst success: false.

Testen — 15-Minuten-Checkliste

Google-reCAPTCHA-Konsole

  1. Key-Typ: v3, Domains: Produktion + optional localhost.
  2. Site Key (öffentlich) und Secret kopieren → RECAPTCHA_SECRET_KEY auf Vercel.
  3. Nach Deploy: Tab Overview — Anfragen für Action submit_contact_form steigen.

DevTools

  1. Network → Submit → JSON mit recaptchaToken (langer String).
  2. Response 200 nur bei OK-Score.
  3. Bewusst ohne Token senden (curl) → 400.

Niedrigen Score simulieren

Google bietet in v3 keinen „Bot-Schalter“; Test-Keys aus der Doku oder temporär niedrigere Schwelle auf Staging.

Checkliste vor Google-Ads-Kampagne

  • Secret auf Produktion gesetzt
  • lazyOnload + 12 s Timeout auf ready
  • Hinweis am Formular in allen Locales
  • Rate Limit aktiv
  • Chatbot (falls öffentlich) — gleiche Prüfung wie Formular
  • Server-Logs ohne Secret-Leak

Performance vs. Sicherheit

lazyOnload für reCAPTCHA ist derselbe Kompromiss wie bei Google-Ads-Tags: LCP wichtiger als sofortige Captcha-Bereitschaft. B2B-Formulare werden meist nach 30+ Sekunden ausgefüllt — dann ist das Skript geladen. Ausnahme: Landing mit Formular above the fold und sehr kurzer Entscheidungszeit — afterInteractive nur für reCAPTCHA oder Preload auf der Kontaktseite.

reCAPTCHA nicht auf jeder Blog-Seite laden, wenn nur auf der Startseite ein Formular ist — dieses Projekt nutzt ein globales Skript (einfacher), bei Performance-Tuning <Script> nur dort, wo <form> steht.

Typische Implementierungsfehler (und wie man sie vermeidet)

  1. Secret nur in .env.local, nicht auf Vercel — lokal OK, Produktion antwortet mit 500 „reCAPTCHA-Konfiguration unvollständig“. Nach jedem neuen Environment RECAPTCHA_SECRET_KEY im Hosting-Dashboard prüfen.
  2. Verifizierung nur wenn Token da ist — im guten Muster bedeutet fehlendes Token Blockade, nicht „durchwinken wegen Adblock“. In /api/submissions führt leeres recaptchaToken zu 400.
  3. Derselbe Token zweimal — Doppelklick auf „Senden“; zweite Anfrage erhält timeout-or-duplicate. UI sollte den Button nach erstem Klick deaktivieren (isSubmitting in React).
  4. Keine action in execute — erschwerte Analyse in der Google-Konsole; immer aussagekräftige Action-Namen pro Formular.
  5. Vollständiges Token in Produktionslogs — auch Einmal-Tokens gehören nicht in öffentliche Logs oder Sentry-Breadcrumbs.

Mehrsprachigkeit (/pl, /en, /de)

Das reCAPTCHA-Skript im gemeinsamen layout.tsx gilt für alle Locales — keine Keys pro Sprache duplizieren. Der Rechtstext kommt aus Übersetzungsdateien (messages/*.json), jede Sprachversion hat korrekte Google-Links ohne Hardcode in der Komponente. API-Fehlermeldungen (400/429) sollten perspektivisch ebenfalls nach locale aus dem Body lokalisiert werden — derzeit sind Teile unabhängig von /en auf Polnisch, was beim Backend-i18n-Refactoring nachgezogen werden sollte.

Integration mit E-Mail und CRM

Nach erfolgreicher reCAPTCHA-Prüfung legt /api/submissions den Lead in Prisma an und versendet Transaktions-Mails (Admin + Bestätigung an den Kunden) über sendTransactionalEmail. Spam, der reCAPTCHA passiert, landet trotzdem im Postfach — deshalb Rate Limit und optional Honeypot vor dem teuren E-Mail-Versand. Score-Werte müssen nicht ins CRM; reicht serverseitiges Logging mit IP-Zeitstempel für spätere Schwellen-Anpassung. Bei hohem Spam-Aufkommen: Score-Schwelle erhöhen oder verdächtige Domains in einer einfachen Blockliste auf API-Ebene filtern — nach reCAPTCHA, nicht stattdessen.

Vergleich mit anderen Anti-Spam-Methoden

Methode Stärke Schwäche
reCAPTCHA v3 Verhaltensanalyse, unsichtbar Google-Abhängigkeit, DSGVO-Hinweis
Honeypot Einfach, kostenlos Leicht von gezielten Bots umgangen
Rate Limit Stoppt Floods Kein Schutz bei vielen IPs
E-Mail-Double-Opt-in Qualität der Adressen Kein Bot-Schutz vor Submit
Akismet / ML-Filter Gut für Kommentare Weniger Standard für B2B-Formulare

Die produktive Kombination in diesem Projekt: Rate Limit + reCAPTCHA v3 + (optional) Honeypot — drei Schichten mit unterschiedlichen Angriffsvektoren.

FAQ

Darf der Site Key im Repo liegen?

Ja — Site Key ist öffentlich (im HTML sichtbar). Secret Key niemals — nur Server-Umgebungsvariablen.

Reicht clientseitige Prüfung?

Nein. Token lassen sich aus DevTools kopieren oder wiederverwenden. Entscheidung muss serverseitig nach siteverify fallen.

Warum bleibt das Token trotz Layout-Skript leer?

Meist execute vor grecaptcha.ready oder Skript durch Adblocker blockiert. Lösung: Polling + Timeout wie in page.tsx.

Ist 0,5 offizielle Google-Empfehlung?

Google erklärt Score-Interpretation, nicht eine feste Schwelle. 0,5 ist praktischer Default — am eigenen Traffic kalibrieren.

reCAPTCHA v3 vs. Cloudflare Turnstile?

Turnstile oft leichter und einfacheres UX; reCAPTCHA v3 passt zum Google-Ökosystem. Marke ist weniger wichtig als serverseitige Prüfung + Rate Limit.

Muss das Badge sichtbar sein?

Ja — Google-Nutzungsbedingungen. Platzierung stylen (wie im Projekt: kleines Icon + Volltext am Formular).

Zusammenfassung

Wirksamer Formular-Schutz ist nicht Tutorial-Skript einfügen, sondern eine konsistente Pipeline: lazyOnload im Layout, geduldiges execute nach ready, pflichtige siteverify mit Score-Schwelle, Rate Limit an der API, DSGVO-Hinweis beim Submit und dasselbe Schema für den Chatbot. 0,5 ist der Startpunkt — aus Logs nachjustieren. Bei False Positives Schwelle senken oder Honeypot ergänzen, statt Schutz ganz abzuschalten.

Formulare absichern lassen?

  • Kontakt — reCAPTCHA v3, Rate Limits und Anti-Spam-Audit für Ihre Website
  • Webseiten — Next.js, Lead-Formulare und DSGVO aus einer Hand
  • Referenzen — Produktivseiten mit unsichtbarem Bot-Schutz

Über den Autor

Wir bauen schnelle Websites, Web/Mobile-Apps, KI-Chatbots und Hosting — mit Fokus auf SEO und Conversion.

Empfohlene Links

Von Theorie zu Produktion — Branchly, Hosting-Stack, Betreuung und Referenzen.

GEFÄLLT EUCH UNSERE ARCHITEKTUR DES DENKENS? LASST UNS GEMEINSAM BAUEN.

[ PROJEKT_KONFIGURATION_STARTEN ]