Formulario de feedback para un sitio web o una app

Formulario de feedback para un sitio web o una app6 min de lectura

Recoge el feedback de los beta testers build a build

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ó.

Preet SutharFundador, Ikiform

Da a cada tester un enlace personal con un código de tester opaco y el número de build, para que el formulario sepa quién responde y sobre qué build sin preguntarlo. Pregunta para qué usaron la build, dos valoraciones de 1 a 5 de estabilidad y utilidad, y qué les frenó. Después compara builds, no respuestas sueltas, para ver si cada versión movió los números.

Qué cambia en el feedback de una beta

El feedback público viene de desconocidos, una sola vez. El feedback de una beta viene del mismo grupo pequeño de personas, una y otra vez, sobre un software que cambia cada semana. Una respuesta suelta importa menos que la tendencia: ¿la build 1.4.0 les pareció más estable que la 1.3.0 a las mismas personas? Para eso hacen falta dos cosas que un formulario de feedback normal no tiene: quién respondió y en qué build estaba.

Pedir a los testers que escriban su email y su número de versión falla en la práctica. Olvidan la versión, la escriben mal o ponen "la última". Así que ambos van en el enlace que envías, y la página los rellena.

El ciclo semanal de feedback de la beta, de una build nueva a la siguientesalelabuild1.4.0algrupode labetaemaildeinvitaciónunenlaceportestereltesterrespondecódigoybuildrellenadosresumenporbuildmedias,testers,loecharíandemenosbuild1.5.0arreglalosbloqueosprincipales?t=…&build=APIEl ciclo semanal de feedback de la beta, de una build nueva a la siguientesale la build 1.4.0al grupo de la betaemail de invitaciónun enlace por testerel tester respondecódigo y build rellenadosresumen por buildmedias, testers, lo echarían demenosbuild 1.5.0arregla los bloqueos principales?t=…&build=API
  1. Sale una build nueva para el grupo de la beta.
  2. Un script crea un enlace por tester con su código y el número de build, y se los envías por email.
  3. El tester abre el enlace. La página rellena los campos ocultos de tester y build y muestra por qué build pregunta.
  4. Un script de resumen lee todas las respuestas a través de la API y promedia las puntuaciones por build.
  5. Los bloqueos de las puntuaciones más bajas se convierten en la lista de arreglos de la siguiente build.
Compara columnas, no filas. La mala semana de un tester es ruido; una caída en todo el grupo es una regresión.

Los campos

Vista previa

Ejecuta el validador de Ikiform en tu navegador. No se envía nada.

¿Qué tan estable te pareció?
¿Qué tan útil fue?
Si ya no pudieras usarlo, ¿cómo te sentirías?
tester y build son inputs ocultos que se rellenan desde el enlace. Sus patrones rechazan todo lo que no venga de una invitación real.
CampoPor qué
testerUn código aleatorio de 10 caracteres. Te permite seguir a una persona entre builds sin poner su email en una URL
buildVincula cada puntuación a una versión. El patrón solo acepta versiones como 1.4.0
triedLo que hicieron realmente. Sin esto, las puntuaciones son difíciles de interpretar
stability, usefulnessDos campos rating, de 1 a 5. Separados, porque una build estable de algo equivocado sigue siendo algo equivocado
would_missLo decepcionados que estarían sin él. Una proporción creciente de "Muy" es la señal más clara de que la beta funciona
blockersOpcional, y de donde sale la lista de arreglos

Guarda una lista simple de emails de testers en testers.txt. Este script asigna a cada uno un código estable la primera vez que lo ve, guarda la correspondencia en testers.json y escribe un enlace de invitación por tester para la build que indiques. Empieza testers.json como {}.

links.mjs
import { randomBytes } from "node:crypto";
import { readFileSync, writeFileSync } from "node:fs";

const BUILD = process.argv[2];
if (!/^\d+\.\d+\.\d+$/.test(BUILD ?? "")) throw new Error("Usage: node links.mjs 1.4.0");

const known = JSON.parse(readFileSync("testers.json", "utf8"));
const emails = readFileSync("testers.txt", "utf8").split(/\r?\n/).map((line) => line.trim().toLowerCase()).filter(Boolean);

for (const email of emails) {
  known[email] ??= randomBytes(5).toString("hex");
}
writeFileSync("testers.json", JSON.stringify(known, null, 2));

const rows = emails.map((email) => {
  const link = new URL("https://example.com/beta/feedback");
  link.searchParams.set("t", known[email]);
  link.searchParams.set("build", BUILD);
  return `${email},${link}`;
});
writeFileSync(`invites-${BUILD}.csv`, ["email,link", ...rows].join("\n"));
console.log(`${rows.length} links for build ${BUILD}`);

Envía el CSV con la combinación de correspondencia de tu herramienta de email, o pega los enlaces a mano si el grupo es pequeño. Mantén testers.json en privado: es el único sitio donde un código se relaciona con una persona.

La página de feedback

Ponlo en una página en /beta/feedback de tu sitio. Lee el código y la build del enlace, no muestra el formulario sin ellos y envía de la forma normal. Configura Redirect after submit con una página de agradecimiento. Funciona en cualquier hosting estático o creador de sitios que permita un script.

beta/feedback.html
<p id="beta-missing" hidden>This page needs the link from your invite email.</p>

<form id="beta" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post" hidden>
  <h2>Feedback for build <span id="beta-build"></span></h2>
  <input type="hidden" name="tester" />
  <input type="hidden" name="build" />
  <label for="tried">What did you use this build for?</label>
  <textarea id="tried" name="tried" rows="4" required minlength="15"></textarea>
  <fieldset>
    <legend>How stable did it feel?</legend>
    <label><input type="radio" name="stability" value="1" required /> 1, it crashed a lot</label>
    <label><input type="radio" name="stability" value="2" /> 2</label>
    <label><input type="radio" name="stability" value="3" /> 3</label>
    <label><input type="radio" name="stability" value="4" /> 4</label>
    <label><input type="radio" name="stability" value="5" /> 5, no problems</label>
  </fieldset>
  <fieldset>
    <legend>How useful was it?</legend>
    <label><input type="radio" name="usefulness" value="1" required /> 1, not at all</label>
    <label><input type="radio" name="usefulness" value="2" /> 2</label>
    <label><input type="radio" name="usefulness" value="3" /> 3</label>
    <label><input type="radio" name="usefulness" value="4" /> 4</label>
    <label><input type="radio" name="usefulness" value="5" /> 5, I rely on it</label>
  </fieldset>
  <fieldset>
    <legend>If you could no longer use it, how would you feel?</legend>
    <label><input type="radio" name="would_miss" value="very" required /> Very disappointed</label>
    <label><input type="radio" name="would_miss" value="somewhat" /> Somewhat disappointed</label>
    <label><input type="radio" name="would_miss" value="not" /> Not disappointed</label>
  </fieldset>
  <label for="blockers">Anything that stopped you?</label>
  <textarea id="blockers" name="blockers" rows="3"></textarea>
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send this week's feedback</button>
</form>

<script>
  const params = new URLSearchParams(location.search);
  const tester = params.get("t") ?? "";
  const build = params.get("build") ?? "";
  const form = document.getElementById("beta");
  if (/^[a-z0-9]{10}$/.test(tester) && /^\d+\.\d+\.\d+$/.test(build)) {
    form.elements.tester.value = tester;
    form.elements.build.value = build;
    document.getElementById("beta-build").textContent = build;
    form.hidden = false;
  } else {
    document.getElementById("beta-missing").hidden = false;
  }
</script>
Cualquiera con el enlace de un tester puede responder como ese tester. Para una beta es aceptable: los códigos son aleatorios, el grupo es pequeño y una respuesta rara se nota. No uses el código para dar acceso a nada.

Compara builds

El panel muestra las respuestas individuales. Para comparar builds, léelas todas con el SDK y agrúpalas por build. Ejecútalo con una clave secreta en IKIFORM_SECRET_KEY:

summary.mjs
import { createClient } from "@ikiform/sdk";

const ikiform = createClient({ apiKey: process.env.IKIFORM_SECRET_KEY });
const builds = new Map();

for await (const submission of ikiform.submissions.iterate({ formId: "frm_xxxxxxxxxxxxxxxx", status: "received" })) {
  const { build, tester, stability, usefulness, would_miss } = submission.fields;
  const row = builds.get(build) ?? { testers: new Set(), stability: 0, usefulness: 0, very: 0, answers: 0 };
  row.testers.add(tester);
  row.stability += stability;
  row.usefulness += usefulness;
  row.very += would_miss === "very" ? 1 : 0;
  row.answers += 1;
  builds.set(build, row);
}

console.table(
  [...builds].map(([build, row]) => ({
    build,
    testers: row.testers.size,
    stability: (row.stability / row.answers).toFixed(1),
    usefulness: (row.usefulness / row.answers).toFixed(1),
    "very disappointed": `${Math.round((row.very / row.answers) * 100)}%`,
  })),
);

Las valoraciones llegan como números, así que las medias no necesitan parseo. Cuenta los testers junto a cada media: una build con tres respuestas no se puede comparar de forma justa con una que tiene treinta.

Comprueba que funciona

  1. Ejecuta node links.mjs 1.4.0 y abre uno de los enlaces. El formulario muestra "Feedback for build 1.4.0".
  2. Abre la página sin la query string. Solo se muestra el mensaje de invitación.
  3. Envía una respuesta, luego cambia build a latest en las herramientas de desarrollo del navegador y vuelve a enviar. Ikiform responde 422 con "Use a version like 1.4.0".
  4. Ejecuta summary.mjs. La tabla muestra la build 1.4.0 con un tester y tus dos puntuaciones.

Errores comunes

  • Los grupos de beta suelen probar desde una misma oficina, que comparte IP. El límite Standard los cuenta juntos, así que elige Relaxed, 20 por minuto por visitante, para este formulario.
  • Las betas móviles en TestFlight ya permiten a los testers enviar feedback con capturas a App Store Connect. Usa eso para los bugs de pantalla y este formulario para las preguntas semanales.
  • Haz las mismas preguntas cada semana. Cambiar la redacción rompe la comparación entre builds.
  • Los testers responden menos a medida que avanza la beta. Mantén el formulario en un par de minutos y agradece a la gente por su nombre en las notas de la versión.
  • Ikiform no fusiona respuestas repetidas. Si un tester responde dos veces para una build, quédate con la última en tu resumen.

Solución de problemas

ProblemaQué hacer
422 con "Open the link from your invite email"El valor de tester no coincide con el patrón, normalmente porque el cliente de email cortó el enlace. Vuelve a enviar el enlace.
429 rate_limitedUn 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.
403 origin_not_allowed, o todos los envíos acaban en spamEl 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.

Preguntas

¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.