Formulário de feedback para um site ou app

Formulário de feedback para um site ou app6 min de leitura

Colete o feedback dos beta testers build a build

Um formulário de feedback de beta com um link pessoal por tester e build, duas escalas de nota e um resumo semanal que mostra se cada build melhorou.

Preet SutharFundador, Ikiform

Dê a cada tester um link pessoal que leva um código opaco do tester e o número do build, para que o formulário saiba quem é e qual build sem perguntar. Pergunte para que a pessoa usou o build, duas notas de 1 a 5 para estabilidade e utilidade, e o que a travou. Depois compare builds, não respostas individuais, para ver se cada release mexeu nos números.

O que muda no feedback de beta

O feedback público vem de desconhecidos, uma vez. O feedback de beta vem do mesmo pequeno grupo de pessoas, de novo e de novo, sobre um software que muda toda semana. Uma resposta isolada importa menos que a tendência: o build 1.4.0 pareceu mais estável que o 1.3.0 para as mesmas pessoas? Isso exige duas coisas que um formulário de feedback normal não tem: quem respondeu e em qual build estava.

Pedir aos testers que digitem o e-mail e o número da versão falha na prática. Eles esquecem a versão, digitam errado ou escrevem "a mais recente". Então as duas coisas vão no link que você envia, e a página as preenche.

O ciclo semanal de feedback de beta, de um build novo até o próximobuild1.4.0saiparaogrupodebetae-maildeconviteumlinkportestertesterrespondecódigoebuildpreenchidosresumoporbuildmédias,testers,sentiriafaltabuild1.5.0corrigeosmaioresbloqueios?t=…&build=APIO ciclo semanal de feedback de beta, de um build novo até o próximobuild 1.4.0 saipara o grupo de betae-mail de conviteum link por testertester respondecódigo e build preenchidosresumo por buildmédias, testers, sentiria faltabuild 1.5.0corrige os maiores bloqueios?t=…&build=API
  1. Um build novo é liberado para o grupo de beta.
  2. Um script gera um link por tester com o código dele e o número do build, e você os envia por e-mail.
  3. O tester abre o link. A página preenche os campos ocultos de tester e build e mostra sobre qual build está perguntando.
  4. Um script de resumo lê todas as respostas pela API e tira a média das notas por build.
  5. Os bloqueios das notas mais baixas viram a lista de correções do próximo build.
Compare colunas, não linhas. Uma semana ruim de um tester é ruído; uma queda no grupo todo é uma regressão.

Os campos

Prévia

Roda o validador do Ikiform no seu navegador. Nada é enviado.

Quão estável ele pareceu?
Quão útil ele foi?
Se você não pudesse mais usá-lo, como se sentiria?
tester e build são inputs ocultos preenchidos a partir do link. Os padrões deles rejeitam qualquer coisa que não veio de um convite real.
CampoPor quê
testerUm código aleatório de 10 caracteres. Permite acompanhar uma pessoa ao longo dos builds sem colocar o e-mail dela numa URL
buildLiga cada nota a um release. O padrão só aceita versões como 1.4.0
triedO que a pessoa realmente fez. Notas sem isso são difíceis de interpretar
stability, usefulnessDois campos rating, de 1 a 5. Separados, porque um build estável da coisa errada continua sendo a coisa errada
would_missO quanto a pessoa ficaria decepcionada sem ele. Uma parcela crescente de "Muito" é o sinal mais forte de que o beta está funcionando
blockersOpcional, e é daqui que sai a lista de correções

Mantenha uma lista simples de e-mails dos testers em testers.txt. Este script dá a cada um um código estável na primeira vez que o vê, guarda o mapeamento em testers.json e escreve um link de convite por tester para o build que você indicar. Comece 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}`);

Envie o CSV pela mala direta da sua ferramenta de e-mail, ou cole os links à mão para um grupo pequeno. Mantenha testers.json privado: é o único lugar onde um código leva de volta a uma pessoa.

A página de feedback

Coloque isto numa página em /beta/feedback no seu site. Ela lê o código e o build do link, se recusa a mostrar o formulário sem eles e envia do jeito tradicional. Defina Redirect after submit para uma página de agradecimento. Funciona em qualquer host estático ou criador de sites que permita um 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>
Qualquer pessoa com o link de um tester pode responder como esse tester. Isso é aceitável para um beta: os códigos são aleatórios, o grupo é pequeno e uma resposta estranha se destaca. Não use o código para conceder acesso a nada.

Compare builds

O painel mostra respostas individuais. Para comparar builds, leia todas com o SDK e agrupe por build. Rode isto com uma chave secreta em 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)}%`,
  })),
);

As notas chegam como números, então as médias não exigem parsing. Conte os testers ao lado de cada média: um build com três respostas não pode ser comparado de forma justa com um que tem trinta.

Confira se funciona

  1. Rode node links.mjs 1.4.0 e abra um dos links. O formulário mostra "Feedback do build 1.4.0".
  2. Abra a página sem a query string. Só a mensagem de convite aparece.
  3. Envie uma resposta, depois mude build para latest nas ferramentas de desenvolvedor do navegador e envie de novo. O Ikiform responde 422 com "Use a version like 1.4.0".
  4. Rode summary.mjs. A tabela mostra o build 1.4.0 com um tester e as suas duas notas.

Pegadinhas

  • Grupos de beta costumam testar de um mesmo escritório, que compartilha um IP. O limite Standard os conta juntos, então escolha Relaxed, 20 por minuto por visitante, para este formulário.
  • Betas mobile no TestFlight já permitem que os testers mandem feedback com captura de tela para o App Store Connect. Use isso para bugs de tela e este formulário para as perguntas semanais.
  • Faça as mesmas perguntas toda semana. Mudar a redação quebra a comparação entre builds.
  • Os testers respondem menos conforme o beta avança. Mantenha o formulário em poucos minutos, e agradeça às pessoas pelo nome nas notas de release.
  • O Ikiform não junta respostas repetidas. Se um tester responder duas vezes para um build, fique com a mais recente no seu resumo.

Solução de problemas

ProblemaO que fazer
422 com "Open the link from your invite email"O valor de tester não bate com o padrão, geralmente porque o link foi cortado num cliente de e-mail. Reenvie o link.
429 rate_limitedUm visitante enviou mais do que o limite de taxa do formulário permite. O Standard permite 5 por minuto por visitante. Espere o Retry-After, ou escolha Relaxed ou Custom para formulários que enviam a partir de um único IP compartilhado.
403 origin_not_allowed, ou todo envio cai no spamO domínio da página não está em Allowed domains do formulário. Adicione-o, mais localhost para testes locais. Subdomínios de um domínio listado são permitidos.

Perguntas

Travou em algum passo ou quer um guia para o seu caso? Envie um e-mail para hello@ikiform.com.