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

Publicado em 2026-10-25 · https://ikiform.com/pt-br/guides/feedback-form/beta-tester-feedback

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.

Diagrama: O ciclo semanal de feedback de beta, de um build novo até o próximo

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

Formulário: Beta feedback

- **Código do tester** (`tester`, text, obrigatório)
- **Build** (`build`, text, obrigatório)
- **Para que você usou este build?** (`tried`, textarea, obrigatório)
- **Quão estável ele pareceu?** (`stability`, rating, obrigatório)
- **Quão útil ele foi?** (`usefulness`, rating, obrigatório)
- **Se você não pudesse mais usá-lo, como se sentiria?** (`would_miss`, radio, obrigatório)
- **Algo travou você?** (`blockers`, textarea)

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

| Campo | Por quê |
| --- | --- |
| `tester` | Um código aleatório de 10 caracteres. Permite acompanhar uma pessoa ao longo dos builds sem colocar o e-mail dela numa URL |
| `build` | Liga cada nota a um release. O padrão só aceita versões como `1.4.0` |
| `tried` | O que a pessoa realmente fez. Notas sem isso são difíceis de interpretar |
| `stability`, `usefulness` | Dois campos `rating`, de 1 a 5. Separados, porque um build estável da coisa errada continua sendo a coisa errada |
| `would_miss` | O quanto a pessoa ficaria decepcionada sem ele. Uma parcela crescente de "Muito" é o sinal mais forte de que o beta está funcionando |
| `blockers` | Opcional, e é daqui que sai a lista de correções |

## Gere um link por tester

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

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

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

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

| Problema | O 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_limited` | Um 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 spam | O 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

### Como sei qual beta tester enviou o feedback?

Dê a cada tester um código aleatório e coloque-o no link pessoal dele. A página o copia para um campo oculto, e só o seu arquivo de mapeamento privado liga o código a um e-mail.

### Como acompanho o feedback por build?

Coloque também o número do build no link, valide com um padrão e agrupe as respostas por build. O submissions.iterate do SDK lê todas as respostas para um resumo.

### Que perguntas um formulário de feedback de beta deve fazer?

Para que a pessoa usou o build, quão estável e quão útil ele pareceu numa escala de 1 a 5, o quanto ela ficaria decepcionada sem ele e o que a travou. Mantenha as mesmas perguntas toda semana.

### Os beta testers devem relatar bugs no mesmo formulário?

Mantenha um formulário de relato de bug separado para tudo o que precisa ser reproduzido. O formulário semanal é sobre a impressão geral do build; misturar os dois deixa ambos mais difíceis de ler.

## Mais guias

- [Formulário de feedback para um site ou app](https://ikiform.com/pt-br/guides/feedback-form.md): Coloque um formulário de feedback em qualquer página ou dentro do seu app: uma nota, um comentário, a página de origem, filtro de spam e alertas para notas baixas.
- [Formulário de relato de bug](https://ikiform.com/pt-br/guides/feedback-form/bug-report.md): Um formulário de relato de bug que pede às pessoas os passos e a gravidade, e deixa a página adicionar sozinha a URL, o navegador, o viewport e os erros recentes.
- [Pesquisa NPS](https://ikiform.com/pt-br/guides/feedback-form/nps-survey.md): Rode uma pesquisa NPS com a nota de 0 a 10 no e-mail, uma pergunta de acompanhamento na sua própria página que muda com a nota e um script que calcula o NPS.
- [Formulário de pedido de funcionalidade](https://ikiform.com/pt-br/guides/feedback-form/feature-request.md): Um formulário de pedido de funcionalidade que pergunta pelo problema em vez da solução, armazena pedidos por tema, conta pessoas, não linhas, e avisa quando sair.
- [Widget de feedback em React](https://ikiform.com/pt-br/guides/feedback-form/react-feedback-widget.md): Um botão de feedback flutuante para um app React que abre um pequeno painel, envia a tela, a versão do app e a conta com cada resposta e nunca perde um rascunho.
- [Pesquisa de cancelamento](https://ikiform.com/pt-br/guides/feedback-form/cancellation-survey.md): Pergunte por que os clientes cancelam dentro do fluxo de cancelamento do seu SaaS, deixe o Pular a um clique, salve o motivo no Stripe e no Ikiform e nunca atrase o cancelamento.
