# Haz una encuesta NPS en tu propio sitio, del enlace en el email a la puntuación

> Haz una encuesta NPS con una puntuación de 0 a 10 en el email, una pregunta de seguimiento en tu propia página que cambia según la puntuación y un script que calcula el NPS.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/feedback-form/nps-survey

Pon once enlaces, del 0 al 10, en el email de la encuesta, cada uno apuntando a una página de tu sitio con la puntuación y un token opaco del encuestado en la URL. La página preselecciona la puntuación, hace una pregunta de seguimiento que depende de ella y no registra nada hasta que la persona pulsa Enviar. Guarda la puntuación en un campo numérico de 0 a 10 y calcula el NPS como el porcentaje de 9 y 10 menos el porcentaje de 0 a 6.

## Qué cambia en el NPS

El NPS hace una sola pregunta con una escala fija: qué probabilidad hay de que nos recomiendes, del 0 al 10. Tres detalles lo diferencian de la valoración de 1 a 5 de la guía principal:

- **La escala empieza en 0.** El campo `rating` de Ikiform va de 1 a 10 como máximo, así que no puede guardar un 0. El NPS usa un campo `number` con `min: 0`, `max: 10` e `integer: true`, guardado como número.
- **Suele enviarse por email.** Los clientes de email no envían formularios ni ejecutan scripts de forma fiable, así que el email lleva enlaces y el formulario vive en tu sitio. Ikiform no tiene páginas de formulario alojadas.
- **Las máquinas hacen clic en los enlaces de los emails.** Muchos escáneres de seguridad del correo abren todos los enlaces de un mensaje para revisarlos. Si abrir un enlace registrara una puntuación, recogerías puntuaciones de escáneres. La página solo registra cuando una persona pulsa Enviar.

Diagrama: Cómo cada franja de puntuaciones NPS tiene su propia pregunta de seguimiento y cuenta para el resultado

1. Una puntuación de 0 a 6 pregunta qué le decepcionó y cuenta como detractor.
2. Un 7 u 8 pregunta qué haría falta para un 10 y solo cuenta para el total.
3. Un 9 o 10 pregunta qué valora más y cuenta como promotor.
4. El NPS es el porcentaje de promotores menos el porcentaje de detractores, de menos 100 a 100.

La pregunta cambia con la puntuación porque la respuesta útil también cambia. El motivo de un detractor es un problema que arreglar; el de un promotor es texto para tu página de inicio.

## Los campos

Formulario: NPS survey

- **¿Qué probabilidad hay de que nos recomiendes a un amigo o colega?** (`score`, number, obligatorio)
- **¿Cuál es el motivo principal de tu puntuación?** (`reason`, textarea)
- **Encuestado** (`respondent`, text)
- **Ronda de la encuesta** (`wave`, text, obligatorio)

Prueba con una puntuación de 11 o 7.5: Ikiform rechaza ambas. También se rechaza si falta `wave`, así que cada respuesta pertenece a una ronda de la encuesta.

| Campo | Por qué |
| --- | --- |
| `score` | `number`, de 0 a 10, solo números enteros. Se guarda como número |
| `reason` | La pregunta de seguimiento. Opcional, porque una puntuación sola también cuenta |
| `respondent` | Un token opaco que generas y envías a cada persona. Se relaciona con el cliente en tu propia base de datos |
| `wave` | Qué ronda, como `2026-q4`. Te permite comparar trimestres sin filtros de fecha |

No pongas el email ni el id de cuenta del cliente en el enlace. Las URL acaban en el historial del navegador, en logs de proxies y en emails reenviados. Un token aleatorio de 16 caracteres o más te dice quién respondió y no le dice nada a nadie más.

## El email de la encuesta

Construye la fila de enlaces con las etiquetas de combinación de tu herramienta de email, o genérala en el código que envía el email. Esta función devuelve el HTML para un encuestado:

`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>`;
}
```

Limita el email a la pregunta y la fila de números. Una introducción larga empuja la escala fuera de la pantalla en los móviles, y la mayoría de respuestas vienen de gente que hace clic en un número sin hacer scroll.

## La página de destino

Ponlo en `/nps` de tu sitio. Dibuja la escala de 0 a 10, preselecciona la puntuación del enlace, pone la pregunta de seguimiento para esa puntuación y envía con `fetch` solo cuando la persona pulsa Enviar. Si cambia la puntuación en la página, la pregunta cambia con ella.

`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>
```

> La página también funciona sin enlace: quien abre `/nps` directamente ve la escala sin nada seleccionado. Su respuesta se rechaza porque falta `wave`, salvo que definas un valor por defecto, lo que deja las visitas sueltas fuera de tus números.

## Calcula la puntuación

Lee todas las respuestas de una ronda con el SDK, quédate con la última respuesta de cada encuestado y aplica la fórmula. Ejecútalo con una clave secreta en `IKIFORM_SECRET_KEY`:

`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}`);
```

El script se queda con una respuesta por encuestado porque a veces la gente hace clic en un segundo número tras cambiar de opinión. Ikiform no fusiona ni rechaza envíos repetidos por email. Una repetición idéntica en 24 horas solo suma a la puntuación de spam. Elimina duplicados donde vive la lista, o al exportar.

## Comprueba que funciona

1. Abre `/nps?score=3&r=test_respondent_0001&wave=2026-q4`. El 3 está seleccionado y la pregunta dice "What disappointed you most?"
2. Haz clic en el 9. La pregunta cambia a "What do you value most about it?"
3. Abre el mismo enlace con `curl`. No aparece nada nuevo en **Submissions**, porque no se envió nada.
4. Pulsa Enviar. La respuesta muestra `score` como el número 9.
5. Ejecuta `node nps.mjs 2026-q4`. Informa de una persona y un promotor.

## Errores comunes

- No encuestes al mismo cliente con demasiada frecuencia. Elige un intervalo, como una vez por trimestre, y guarda la lista de encuestados en tu lado.
- Las muestras pequeñas oscilan mucho. Con 20 respuestas, una persona mueve el NPS 5 puntos. Indica el número de personas junto a la puntuación.
- Las puntuaciones bajas merecen respuesta. Envía a los detractores al chat de tu equipo con un relay de webhook como la [alerta de puntuación baja](https://ikiform.com/es/guides/feedback-form.md#routing) de la guía principal, usando `score <= 6`.
- La [plantilla de formulario](https://ikiform.com/forms/survey) de encuesta hace la pregunta de la puntuación dentro de una encuesta más larga. Eso encaja con un estudio puntual; una pregunta NPS suelta obtiene más respuestas.
- Ikiform no envía emails a la persona que rellena el formulario. Los emails de notificación van solo a ti y a tu equipo, así que no hay respuesta automática, email de confirmación ni doble opt-in. Envíalos desde tu herramienta de email, activada por un [webhook](https://ikiform.com/es/docs/webhooks.md).

## Solución de problemas

| Problema | Qué hacer |
| --- | --- |
| `422` con `Must be at most 10`, o un error de número entero | La puntuación vino de otro sitio que no es la escala, como una URL editada a mano. La página solo acepta del 0 al 10 desde el enlace; revisa los enlaces de tu plantilla de email. |
| `422` que menciona `wave` | El enlace no llevaba `wave`, o no coincide con valores del estilo de `2026-q4`. Arregla la plantilla de email o pon un valor por defecto en el script de la página. |
| `403 origin_not_allowed`, o todos los envíos acaban en spam | El dominio de la página no está en **Allowed domains** del formulario. Añádelo, y `localhost` para las pruebas locales. Los subdominios de un dominio de la lista están permitidos. |
| `429 rate_limited` | Un visitante envió más de lo que permite el límite de frecuencia del formulario. Standard permite 5 por minuto por visitante. Espera lo que indique `Retry-After`, o elige Relaxed o Custom para formularios que envían desde una IP compartida. |

## Preguntas

### ¿Cómo pongo una pregunta NPS en un email?

Pon once enlaces, del 0 al 10, en el email, y que cada uno abra una página de tu sitio con la puntuación en la URL. La página la preselecciona, hace una pregunta de seguimiento y registra la respuesta cuando la persona pulsa Enviar.

### ¿Puedo usar el campo de valoración de Ikiform para el NPS?

No. Una valoración va de 1 a como mucho 10, y el NPS necesita el 0. Usa un campo numérico con min 0, max 10 e integer true.

### ¿Cómo se calcula el NPS?

Toma el porcentaje de respuestas que son 9 o 10, réstale el porcentaje de las que van del 0 al 6, e ignora el 7 y el 8 salvo en el total. El resultado va de menos 100 a 100.

### ¿Por qué no registrar la puntuación en cuanto se hace clic en el enlace?

Los escáneres de seguridad del correo abren los enlaces de los emails entrantes para comprobarlos. Registrar al hacer clic contaría esas visitas como respuestas. Registrar solo al pulsar Enviar mantiene los números honestos.

## Más guías

- [Formulario de feedback para un sitio web o una app](https://ikiform.com/es/guides/feedback-form.md): Pon un formulario de feedback en cualquier página o dentro de tu app: una valoración, un comentario, la página de origen, filtro antispam y avisos cuando la nota es baja.
- [Encuesta de cancelación](https://ikiform.com/es/guides/feedback-form/cancellation-survey.md): Pregunta por qué cancelan tus clientes dentro del flujo de baja de tu SaaS, deja Omitir a un clic, guarda el motivo en Stripe e Ikiform y nunca retrases la baja.
- [Feedback de beta testers](https://ikiform.com/es/guides/feedback-form/beta-tester-feedback.md): Un formulario de feedback para betas con un enlace personal por tester y build, dos escalas de valoración y un resumen semanal que muestra si cada build mejoró.
- [Widget de feedback en React](https://ikiform.com/es/guides/feedback-form/react-feedback-widget.md): Un botón flotante de feedback para una app React que abre un panel pequeño, envía la pantalla, la versión de la app y la cuenta con cada respuesta, y nunca pierde un borrador.
- [Formulario de reporte de bugs](https://ikiform.com/es/guides/feedback-form/bug-report.md): Un formulario de reporte de bugs que pide a la gente los pasos y la gravedad, y deja que la página añada por su cuenta la URL, el navegador, el viewport y los errores recientes.
- [Formulario de peticiones de funcionalidades](https://ikiform.com/es/guides/feedback-form/feature-request.md): Un formulario de peticiones de funcionalidades que pregunta por el problema en lugar de la solución, guarda las peticiones por tema, cuenta personas y no filas, y les avisa por email cuando sale.
