---
type: tutorial
title: Das Widget zu deiner Seite hinzufügen
summary: Füge das Widget zu deinem React-Kontaktformular hinzu, bestätige eine echte Verifizierung im Dashboard und erzwinge sie dann auf deinem Node-Backend.
---

Du hast BananaSeeds Public Key aus der [vorigen Lektion](/docs/getting-started/create-your-account). Jetzt setzen wir das Widget auf das React-Kontaktformular, sehen im Dashboard, wie ein echter Besucher es löst, und fügen dann den einen Server-Aufruf hinzu, der daraus echten Schutz macht.

## Was du am Ende hast

- Das Widget auf deinem Kontaktformular, das Besucher im Browser verifiziert.
- Dein Dashboard, das diese Verifizierungen zeigt.
- Dein Node-Backend, das jede Einsendung ohne gültiges Token verwirft.

## 1. Das Widget zu deinem React-Formular hinzufügen

Installier das Paket. Es registriert das `<caputchin-widget>`-Element (und das `<caputchin-game>`-Element für die nächste Lektion):

```bash
npm install @caputchin/widget
```

Importier es einmal beim Start, etwa in deinem App-Einstieg (`main.jsx`):

```js
import "@caputchin/widget";
```

Jetzt setz das Widget in BananaSeeds Kontaktformular. Wenn die Checkbox gelöst ist, fügt das Widget dem Formular ein verstecktes `caputchin-token`-Feld hinzu, das du beim Absenden genau wie deine eigenen Felder ausliest. Ersetz `cpt_pub_...` durch deinen Public Key:

```jsx
export function ContactForm() {
  async function handleSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.currentTarget);
    await fetch("/api/contact", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        email: data.get("email"),
        message: data.get("message"),
        token: data.get("caputchin-token"),
      }),
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" required />
      <textarea name="message" required />
      <caputchin-widget sitekey="cpt_pub_..." />
      <button type="submit">Send</button>
    </form>
  );
}
```

Auf einer reinen HTML-Seite ohne Build-Schritt oder in einer nativen Mobile-App? Sieh dir [die Script-Tag-Integration (CDN)](/docs/integration-guides/cdn) und [die Mobile-App-Anleitung](/docs/integration-guides/mobile-apps) an.

## 2. Sieh es verifizieren

Starte deine App und öffne das Kontaktformular. Die Caputchin-Checkbox erscheint und schließt sich von selbst, ganz ohne Klick. Du musst das Formular noch nicht einmal absenden: Das ist schon eine echte Verifizierung, und sie hat Caputchin erreicht.

## 3. Bestätige es in deinem Dashboard

Zurück im Dashboard, öffne dein Team und klick in deinen Site-Key. Seine Statistik zeigt einen Funnel: **Sessions gestartet**, **Im Browser bestanden**, **Serverseitig verifiziert** und **Bedrohungen blockiert**. Aktualisier die Seite; **Sessions gestartet** und **Im Browser bestanden** zeigen jetzt beide mindestens `1`. Das ist dein Besuch: Das Widget hat geladen (gestartet) und die Aufgabe wurde im Browser gelöst (im Browser bestanden), ganz ohne Backend.

**Serverseitig verifiziert** steht noch auf `0`, weil noch nichts auf deinem Server ein Token geprüft hat. Diese Lücke ist der nächste Schritt.

<Callout type="success">Dein Widget ist live, und das Dashboard protokolliert schon echte Verifizierungen, bevor du eine Zeile Backend-Code geschrieben hast. 🎉</Callout>

## 4. Verifiziere das Token auf deinem Backend

Im Browser bestanden heißt, der Besucher hat die Aufgabe gelöst, aber dein Formular ist nicht geschützt, bis dein Server das Token bestätigt. Ein Bot kann das Widget komplett ignorieren und direkt an deinen Endpunkt POSTen. Also prüft dein Backend jedes Token mit Caputchin, bevor es der Anfrage traut. Dein Secret (`cpt_sec_...`) lebt in einer Umgebungsvariable, nie im Browser:

```js
import express from "express";

const app = express();
app.use(express.json());

app.post("/api/contact", async (req, res) => {
  const { email, message, token } = req.body;

  const verdict = await fetch("https://verify.caputchin.com/v1/siteverify", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      secret: process.env.CAPUTCHIN_SECRET,
      response: token,
    }),
  }).then((r) => r.json());

  if (!verdict.success) {
    return res.status(400).json({ error: "Could not verify you are human." });
  }

  // Verified. Handle the real message: store it, email it, whatever you do.
  res.json({ ok: true });
});

app.listen(3001);
```

Diese `verdict.success`-Prüfung ist der Punkt: Ein Bot, der direkt an `/api/contact` postet, trägt kein Token, `success` kommt als `false` zurück, und die Nachricht wird verworfen, bevor du sie je anfasst.

Kein Backend? Kein Problem. Schalt [gehostete Verifizierung](/docs/hosted-verification/overview) ein, und Caputchin führt diese Prüfung für dich aus und leitet nur verifizierte Einsendungen an einen Webhook oder deinen Posteingang weiter.

## 5. Bestätige die Server-Prüfung

Sende das Kontaktformular noch einmal ab, jetzt wo dein Endpunkt verifiziert. Geh zurück zur Statistik deines Site-Keys und aktualisier: **Serverseitig verifiziert** zeigt jetzt ebenfalls mindestens `1`, neben Gestartet und Im Browser bestanden. Der ganze Funnel ist abgedeckt, vom Browser bis zum Server.

Um diesen Funnel andersherum zu lesen (was dir die Lücken zwischen den Zählern über Besucher-Abbruch und Integrationsfehler verraten), sieh dir [Statistik und Sessions](/docs/site-keys/statistics) an.

<Callout type="success">Dein Kontaktformular ist jetzt echt geschützt: Jede Einsendung wird auf deinem Server geprüft, und tokenlose Bots werden abgewiesen. 🎉</Callout>

## Was gerade passiert ist

| Schritt | Wo | Ergebnis |
|---|---|---|
| `<caputchin-widget>` in deinem Formular | React | Die Checkbox verifiziert beim Mount und fügt ein Einmal-Feld `caputchin-token` hinzu. |
| Die Seite öffnen | Browser | Gestartet und Im Browser bestanden ticken hoch, kein Backend nötig. |
| `/siteverify` mit deinem Secret | Node zu Caputchin | `success: true` lässt die Anfrage durch; kein Token bedeutet, sie wird verworfen, und Serverseitig verifiziert steigt. |

## Häufige Fragen

### Brauche ich ein Backend, um das Widget zu nutzen?

Für den Browser-Schritt nein. Für echten Schutz ja. Das Widget verifiziert im Browser von selbst, aber ein Bot kann sie ignorieren und direkt an deinen Endpunkt POSTen, also muss dein Server das `caputchin-token` bestätigen, bevor er einer Einsendung traut. Wenn du kein Backend betreibst, schalt [gehostete Verifizierung](/docs/hosted-verification/overview) ein, und Caputchin übernimmt diese Prüfung für dich.

### Warum ist Serverseitig verifiziert immer noch null, nachdem das Widget geladen hat?

Weil noch nichts auf deinem Server ein Token geprüft hat. Gestartet und Im Browser bestanden ticken vom Browser allein; Serverseitig verifiziert steigt erst, sobald dein Backend `/siteverify` aufruft, was [Schritt 4](#4-verifiziere-das-token-auf-deinem-backend) ist.

### Funktioniert das Widget außerhalb von React?

Ja. Es ist ein standardmäßiges Custom Element, also fügt es sich mit demselben einen Tag in pures HTML, Vue, Svelte, Angular oder eine native App-WebView ein. Sieh dir [die clientseitige Integration](/docs/integration-guides/cdn) und [die Mobile-App-Anleitung](/docs/integration-guides/mobile-apps) an.

### Wohin gehört mein Secret Key?

Nur auf deinen Server, in eine Umgebungsvariable (`cpt_sec_...`). Er authentifiziert den `/siteverify`-Aufruf und darf nie an den Browser ausgeliefert werden.

## Weiter

Die Checkbox funktioniert. Jetzt der spaßige Teil: tausch sie gegen ein echtes spielbares Spiel, ohne Änderung an deinem Backend.

Weiter zu [Ein Spiel aus dem Marketplace hinzufügen](/docs/getting-started/add-a-game).
