# NPS-Umfrage auf deiner eigenen Site durchführen, vom E-Mail-Link bis zum Wert

> Führe eine NPS-Umfrage mit einem Wert von 0 bis 10 in der E-Mail durch, mit einer Folgefrage auf deiner eigenen Seite, die sich mit dem Wert ändert, und einem Skript, das den NPS berechnet.

Veröffentlicht am 2026-10-25 · https://ikiform.com/de/guides/feedback-form/nps-survey

Setze elf Links von 0 bis 10 in die Umfrage-E-Mail, die jeweils mit dem Wert und einem undurchsichtigen Teilnehmer-Token in der URL auf eine Seite deiner Site zeigen. Die Seite wählt den Wert vor, stellt eine davon abhängige Folgefrage und speichert nichts, bis die Person auf Senden drückt. Speichere den Wert in einem number-Feld von 0 bis 10 und berechne den NPS als Anteil der 9er und 10er minus den Anteil von 0 bis 6.

## Was am NPS anders ist

NPS stellt eine Frage mit fester Skala: Wie wahrscheinlich empfiehlst du uns weiter, von 0 bis 10. Drei Details unterscheiden ihn von der Bewertung von 1 bis 5 in der Hauptanleitung:

- **Die Skala beginnt bei 0.** Das Feld `rating` von Ikiform reicht von 1 bis höchstens 10, kann also keine 0 aufnehmen. NPS nutzt ein `number`-Feld mit `min: 0`, `max: 10` und `integer: true`, gespeichert als Zahl.
- **Er wird meist per E-Mail verschickt.** E-Mail-Clients senden Formulare nicht zuverlässig ab und führen keine Skripte aus, also enthält die E-Mail Links, und das Formular liegt auf deiner Site. Ikiform hat keine gehosteten Formularseiten.
- **Links in E-Mails werden von Maschinen angeklickt.** Viele Sicherheitsscanner für E-Mails öffnen jeden Link einer Nachricht, um ihn zu prüfen. Würde das Öffnen eines Links einen Wert speichern, würdest du Werte von Scannern sammeln. Die Seite speichert erst, wenn eine Person auf Senden drückt.

Diagramm: Wie jeder NPS-Wertebereich seine eigene Folgefrage bekommt und ins Ergebnis einfließt

1. Ein Wert von 0 bis 6 fragt, was enttäuscht hat, und zählt als Kritiker.
2. Eine 7 oder 8 fragt, was daraus eine 10 machen würde, und zählt nur zur Gesamtzahl.
3. Eine 9 oder 10 fragt, was die Person am meisten schätzt, und zählt als Promoter.
4. NPS ist der Prozentsatz der Promoter minus der Prozentsatz der Kritiker, von minus 100 bis 100.

Die Frage ändert sich mit dem Wert, weil sich die nützliche Antwort ändert. Der Grund eines Kritikers ist ein Problem, das du beheben musst; der eines Promoters ist Text für deine Startseite.

## Die Felder

Formular: NPS survey

- **Wie wahrscheinlich ist es, dass du uns einem Freund oder Kollegen empfiehlst?** (`score`, number, Pflichtfeld)
- **Was ist der Hauptgrund für deinen Wert?** (`reason`, textarea)
- **Teilnehmer** (`respondent`, text)
- **Umfragerunde** (`wave`, text, Pflichtfeld)

Probier einen Wert von 11 oder 7.5: Ikiform lehnt beide ab. Auch ein fehlendes `wave` wird abgelehnt, sodass jede Antwort zu einer Umfragerunde gehört.

| Feld | Warum |
| --- | --- |
| `score` | `number`, 0 bis 10, nur ganze Zahlen. Als Zahl gespeichert |
| `reason` | Die Folgefrage. Optional, weil ein Wert allein auch zählt |
| `respondent` | Ein undurchsichtiges Token, das du pro Person erzeugst und verschickst. Lässt sich in deiner eigenen Datenbank dem Kunden zuordnen |
| `wave` | Welche Runde, etwa `2026-q4`. Damit vergleichst du Quartale ohne Datumsfilter |

Setze weder die E-Mail noch die Konto-ID des Kunden in den Link. URLs landen im Browserverlauf, in Proxy-Logs und in weitergeleiteten E-Mails. Ein zufälliges Token mit 16 oder mehr Zeichen sagt dir, wer geantwortet hat, und allen anderen nichts.

## Die Umfrage-E-Mail

Baue die Linkreihe mit den Merge-Tags deines E-Mail-Tools oder erzeuge sie im Code, der die E-Mail verschickt. Diese Funktion gibt das HTML für einen Teilnehmer zurück:

`nps-email.js`:

```js
function npsRow(respondent, wave) {
  const cells = Array.from({ length: 11 }, (_, score) => {
    const link = new URL("https://example.com/nps");
    link.searchParams.set("score", String(score));
    link.searchParams.set("r", respondent);
    link.searchParams.set("wave", wave);
    return `<td><a href="${link}" style="display:block;padding:8px 10px">${score}</a></td>`;
  });
  return `<table role="presentation"><tr>${cells.join("")}</tr></table>
<p>0 is not at all likely, 10 is extremely likely.</p>`;
}
```

Beschränke die E-Mail auf die Frage und die Zahlenreihe. Eine lange Einleitung schiebt die Skala auf Smartphones aus dem sichtbaren Bereich, und die meisten Antworten kommen von Leuten, die ohne zu scrollen eine Zahl anklicken.

## Die Landingpage

Setze das unter `/nps` auf deine Site. Die Seite zeichnet die Skala von 0 bis 10, wählt den Wert aus dem Link vor, setzt die Folgefrage für diesen Wert und sendet erst per `fetch`, wenn die Person auf Senden drückt. Ändert sie den Wert auf der Seite, ändert sich die Frage mit.

`nps.html`:

```html
<form id="nps" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <fieldset>
    <legend>How likely are you to recommend us to a friend or colleague?</legend>
    <div id="nps-scale"></div>
  </fieldset>
  <label for="reason" id="reason-label">What's the main reason for your score?</label>
  <textarea id="reason" name="reason" rows="4" maxlength="4000"></textarea>
  <input type="hidden" name="respondent" />
  <input type="hidden" name="wave" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send</button>
  <p id="nps-status" role="status"></p>
</form>

<script>
  const QUESTIONS = [
    [6, "What disappointed you most?"],
    [8, "What would make it a 10 for you?"],
    [10, "What do you value most about it?"],
  ];
  const params = new URLSearchParams(location.search);
  const form = document.getElementById("nps");
  const label = document.getElementById("reason-label");
  const scale = document.getElementById("nps-scale");

  for (let score = 0; score <= 10; score += 1) {
    scale.insertAdjacentHTML(
      "beforeend",
      `<label><input type="radio" name="score" value="${score}" required /> ${score}</label>`,
    );
  }

  function askFor(score) {
    label.textContent = QUESTIONS.find(([top]) => score <= top)[1];
  }

  const preset = Number(params.get("score"));
  if (params.has("score") && Number.isInteger(preset) && preset >= 0 && preset <= 10) {
    form.elements.score.value = String(preset);
    askFor(preset);
  }
  form.elements.respondent.value = params.get("r") ?? "";
  form.elements.wave.value = params.get("wave") ?? "";
  scale.addEventListener("change", (event) => askFor(Number(event.target.value)));

  form.addEventListener("submit", async (event) => {
    event.preventDefault();
    const status = document.getElementById("nps-status");
    status.textContent = "Sending";
    const response = await fetch(form.action, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(form),
    }).catch(() => null);
    const result = await response?.json().catch(() => null);
    if (result?.ok) {
      form.replaceChildren(Object.assign(document.createElement("p"), { textContent: "Thanks for answering." }));
      return;
    }
    status.textContent = result?.error?.fields?.score?.[0] ?? result?.error?.message ?? "Couldn't send it. Try again.";
  });
</script>
```

> Die Seite funktioniert auch ohne Link: Wer `/nps` direkt öffnet, sieht die Skala ohne Auswahl. Seine Antwort wird wegen eines fehlenden `wave` abgelehnt, außer du setzt einen Standardwert, was zufällige Besuche aus deinen Zahlen heraushält.

## Den Wert berechnen

Lies mit dem SDK jede Antwort einer Runde, behalte pro Teilnehmer die neueste Antwort und wende die Formel an. Führe es mit einem Secret Key in `IKIFORM_SECRET_KEY` aus:

`nps.mjs`:

```js
import { createClient } from "@ikiform/sdk";

const WAVE = process.argv[2] ?? "2026-q4";
const ikiform = createClient({ apiKey: process.env.IKIFORM_SECRET_KEY });
const latest = new Map();

for await (const submission of ikiform.submissions.iterate({ formId: "frm_xxxxxxxxxxxxxxxx", status: "received" })) {
  const { score, respondent, wave } = submission.fields;
  if (wave !== WAVE) continue;
  const key = respondent || submission.id;
  const seen = latest.get(key);
  if (!seen || seen.at < submission.created_at) latest.set(key, { score, at: submission.created_at });
}

const scores = [...latest.values()].map((answer) => answer.score);
const promoters = scores.filter((value) => value >= 9).length;
const detractors = scores.filter((value) => value <= 6).length;
const nps = Math.round(((promoters - detractors) / scores.length) * 100);

console.log(`${WAVE}: ${scores.length} people, ${promoters} promoters, ${detractors} detractors, NPS ${nps}`);
```

Das Skript behält eine Antwort pro Teilnehmer, weil Leute manchmal eine zweite Zahl anklicken, nachdem sie es sich anders überlegt haben. Ikiform führt wiederholte Einsendungen nicht nach E-Mail zusammen und lehnt sie nicht ab. Eine identische Wiederholung innerhalb von 24 Stunden erhöht nur den Spam-Score. Entferne Duplikate dort, wo die Liste liegt, oder beim Export.

## Prüfen, ob es funktioniert

1. Öffne `/nps?score=3&r=test_respondent_0001&wave=2026-q4`. Die 3 ist ausgewählt, und die Frage lautet „What disappointed you most?“
2. Klick auf 9. Die Frage ändert sich zu „What do you value most about it?“
3. Öffne denselben Link mit `curl`. Unter **Submissions** erscheint nichts Neues, weil nichts gesendet wurde.
4. Drück auf Senden. Die Antwort zeigt `score` als die Zahl 9.
5. Führe `node nps.mjs 2026-q4` aus. Es meldet eine Person und einen Promoter.

## Stolperfallen

- Befrage denselben Kunden nicht zu oft. Wähle ein Intervall, etwa einmal pro Quartal, und führe die Teilnehmerliste auf deiner Seite.
- Kleine Stichproben schwanken stark. Bei 20 Antworten verschiebt eine Person den NPS um 5 Punkte. Nenne neben dem Wert die Zahl der Personen.
- Niedrige Werte verdienen eine Antwort. Schick Kritiker mit einem Webhook-Relay wie dem [Alert für niedrige Bewertungen](https://ikiform.com/de/guides/feedback-form.md#routing) der Hauptanleitung in deinen Team-Chat, mit `score <= 6`.
- Die [Umfrage-Vorlage](https://ikiform.com/forms/survey) fragt den Wert innerhalb einer längeren Umfrage ab. Das passt zu einer einmaligen Studie; eine eigenständige NPS-Frage bekommt mehr Antworten.
- Ikiform schickt der Person, die das Formular ausfüllt, keine E-Mail. Benachrichtigungs-E-Mails gehen nur an dich und dein Team, es gibt also keinen Autoresponder, keine Bestätigungs-E-Mail und kein Double-Opt-in. Verschicke sie aus deinem E-Mail-Tool, ausgelöst durch einen [Webhook](https://ikiform.com/de/docs/webhooks.md).

## Fehlerbehebung

| Problem | Was zu tun ist |
| --- | --- |
| `422` mit `Must be at most 10` oder einem Fehler zu ganzen Zahlen | Der Wert kam nicht von der Skala, etwa aus einer von Hand bearbeiteten URL. Die Seite akzeptiert aus dem Link nur 0 bis 10; prüf die Links in deiner E-Mail-Vorlage. |
| `422` mit Nennung von `wave` | Der Link enthielt kein `wave`, oder der Wert passt nicht zum Format `2026-q4`. Korrigiere die E-Mail-Vorlage oder setze einen Standardwert im Skript der Seite. |
| `403 origin_not_allowed`, oder jeder Post landet im Spam | Die Domain der Seite steht nicht unter **Allowed domains** des Formulars. Füge sie hinzu, plus `localhost` für lokale Tests. Subdomains einer eingetragenen Domain sind erlaubt. |
| `429 rate_limited` | Ein Besucher hat mehr gesendet, als das Rate-Limit des Formulars erlaubt. Standard erlaubt 5 pro Minute und Besucher. Warte `Retry-After` ab oder wähle Relaxed oder Custom für Formulare, die von einer gemeinsamen IP aus senden. |

## Fragen

### Wie setze ich eine NPS-Frage in eine E-Mail?

Setze elf Links von 0 bis 10 in die E-Mail, die jeweils eine Seite deiner Site mit dem Wert in der URL öffnen. Die Seite wählt ihn vor, stellt eine Folgefrage und speichert die Antwort, wenn die Person auf Senden drückt.

### Kann ich das rating-Feld von Ikiform für NPS nutzen?

Nein. Ein rating reicht von 1 bis höchstens 10, und NPS braucht die 0. Nutze ein number-Feld mit min 0, max 10 und integer true.

### Wie wird der NPS berechnet?

Nimm den Prozentsatz der Antworten mit 9 oder 10, zieh den Prozentsatz mit 0 bis 6 ab und ignoriere 7 und 8 außer in der Gesamtzahl. Das Ergebnis reicht von minus 100 bis 100.

### Warum den Wert nicht schon beim Klick auf den Link speichern?

Sicherheitsscanner für E-Mails öffnen Links in eingehenden E-Mails, um sie zu prüfen. Beim Klick zu speichern würde diese Besuche als Antworten zählen. Erst beim Senden zu speichern, hält die Zahlen ehrlich.

## Weitere Anleitungen

- [Feedback-Formular für eine Website oder App](https://ikiform.com/de/guides/feedback-form.md): Setze ein Feedback-Formular auf jede Seite oder in deine App: eine Bewertung, ein Kommentar, die Herkunftsseite, Spamfilter und Alerts bei niedrigen Werten.
- [Kündigungsumfrage](https://ikiform.com/de/guides/feedback-form/cancellation-survey.md): Frag im Kündigungsablauf deines SaaS, warum Kunden kündigen, halte Überspringen einen Klick entfernt, speichere den Grund in Stripe und Ikiform und verzögere die Kündigung nie.
- [Feedback von Beta-Testern](https://ikiform.com/de/guides/feedback-form/beta-tester-feedback.md): Ein Beta-Feedback-Formular mit einem persönlichen Link pro Tester und Build, zwei Bewertungsskalen und einer Wochenübersicht, die zeigt, ob jeder Build besser wurde.
- [Feedback-Widget für React](https://ikiform.com/de/guides/feedback-form/react-feedback-widget.md): Ein schwebender Feedback-Button für eine React-App, der ein kleines Panel öffnet, Ansicht, App-Version und Konto mit jeder Antwort sendet und nie einen Entwurf verliert.
- [Formular für Bug-Reports](https://ikiform.com/de/guides/feedback-form/bug-report.md): Ein Bug-Report-Formular, das nach Schritten und Schweregrad fragt und URL, Browser, Viewport und letzte Fehler von der Seite selbst ergänzen lässt.
- [Formular für Feature-Wünsche](https://ikiform.com/de/guides/feedback-form/feature-request.md): Ein Formular für Feature-Wünsche, das nach dem Problem statt nach der Lösung fragt, Wünsche nach Thema speichert, Personen statt Zeilen zählt und sie beim Release anschreibt.
