Formulaire de feedback pour un site ou une application7 min de lecture
Recueillir des demandes de fonctionnalités que vous pouvez compter, classer et suivre
Un formulaire de demande de fonctionnalité qui demande le problème plutôt que la solution, range les demandes par thème, compte les personnes et non les lignes, et les prévient quand c'est livré.
Demandez ce que la personne essaie de faire et comment elle s'y prend aujourd'hui, pas quelle fonctionnalité elle veut, et exigez un e-mail pour la prévenir quand c'est livré. Stockez chaque demande dans une table via webhook, regroupez les demandes par thème et classez les thèmes selon le nombre de personnes différentes bloquées. Quand un thème est livré, écrivez à tous ceux qui l'ont demandé.
Ce qui change avec les demandes de fonctionnalités
Un signalement de bug est clos quand il est corrigé. Une demande de fonctionnalité est un point de données : une personne parmi beaucoup d'autres qui décrit le même manque avec d'autres mots. Trois conséquences en découlent :
- Les gens décrivent des solutions. « Ajoutez un bouton CSV » peut vouloir dire « mon comptable a besoin des factures du mois dernier ». Demandez le besoin, et vous pourrez choisir une meilleure solution que celle demandée.
- Le même besoin arrive de nombreuses fois. Ikiform stocke chaque envoi et ne fusionne pas les répétitions, et de toute façon deux personnes utilisent rarement les mêmes mots. C'est vous qui regroupez les demandes, par thème, et comptez les personnes distinctes.
- La valeur est dans le suivi. Dire à quelqu'un « vous l'avez demandé, on l'a fait » est la meilleure raison de poser la question. Il faut pour cela un e-mail sur chaque demande, donc ce formulaire l'exige.
- Quelqu'un décrit ce qu'il essaie de faire, choisit un domaine et un impact, et laisse son e-mail.
- Un relais de webhook insère la demande dans votre base de données, une fois par id de soumission.
- Chaque semaine, vous attribuez un thème aux nouvelles demandes, à la main ou avec un motif.
- Si elle correspond à un thème existant, ce thème compte une personne de plus.
- Sinon, elle crée un nouveau thème.
- Quand un thème est livré, vous sélectionnez tous ses e-mails et envoyez un seul message.
Demander le problème
Aperçu
Exécute le validateur d'Ikiform dans votre navigateur. Rien n'est envoyé.
problem exige au moins 30 caractères, ce qui transforme « dark mode svp » en une phrase avec une raison.| Champ | Pourquoi ce champ |
|---|---|
problem | Le besoin, avec leurs mots. De loin le champ le plus utile |
workaround | Indique à quel point c'est pénible. « Je le recopie à la main dans un tableur » est un signal fort |
area | Un premier tri grossier, pour étiqueter dans la facturation et non dans tout le reste |
impact | Distingue les clients bloqués des curieux, formulé en conséquences que les gens peuvent juger |
email | Obligatoire. Sans lui, impossible de les prévenir ou de poser une question |
Laissez de côté tout champ de priorité ou de vote. Chacun marque sa propre demande comme prioritaire, et le nombre de personnes par thème est un meilleur vote que n'importe quel bouton.
Le formulaire
Le formulaire n'a besoin d'aucun script : il envoie et redirige. Réglez Redirect after submit sur une page qui explique la suite. Pour une version qui reste sur la page dans votre framework, reprenez le code du formulaire du guide principal et remplacez-y les champs par ceux-ci.
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<label for="problem">What are you trying to do?</label>
<textarea id="problem" name="problem" rows="5" required minlength="30"
placeholder="Send last month's invoices to our accountant in one go"></textarea>
<label for="workaround">How do you do it today?</label>
<textarea id="workaround" name="workaround" rows="3"></textarea>
<label for="area">Which part of the product?</label>
<select id="area" name="area" required>
<option value="billing">Billing and invoices</option>
<option value="reports">Reports</option>
<option value="team">Team and permissions</option>
<option value="integrations">Integrations and API</option>
<option value="other">Something else</option>
</select>
<fieldset>
<legend>How much does it matter?</legend>
<label><input type="radio" name="impact" value="blocking" required /> It stops us using the product for something</label>
<label><input type="radio" name="impact" value="slow" /> It costs us time every week</label>
<label><input type="radio" name="impact" value="nice" /> It would be nice</label>
</fieldset>
<label for="email">Email</label>
<input id="email" name="email" type="email" required />
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
<button>Send request</button>
</form>Stocker les demandes via webhook
Le tableau de bord et l'export CSV suffisent pour les premières dizaines de demandes. Dès que vous étiquetez des thèmes et comptez les personnes chaque semaine, une table est plus pratique. Créez-en une dans Postgres :
create table feature_requests (
submission_id text primary key,
area text not null,
impact text not null,
problem text not null,
workaround text,
email text not null,
theme text,
created_at timestamptz not null
);Ajoutez ensuite dans Ikiform un endpoint de webhook qui pointe vers cette route. Elle tourne sur n'importe quel hébergeur Node avec le package pg, et votre propre serveur détaille le même principe :
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const INSERT = `insert into feature_requests (submission_id, area, impact, problem, workaround, email, created_at)
values ($1, $2, $3, $4, $5, lower($6), $7)
on conflict (submission_id) do nothing`;
export async function POST(request: Request) {
const payload = await request.text();
let event;
try {
event = await verifyWebhook({
payload,
headers: request.headers,
secret: process.env.IKIFORM_WEBHOOK_SECRET!,
});
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
throw error;
}
if (event.type !== "submission.created") return new Response(null, { status: 204 });
const { problem, workaround, area, impact, email } = event.data.fields;
await pool.query(INSERT, [
event.data.submission_id,
area,
impact,
problem,
workaround ?? null,
email,
event.data.created_at,
]);
return new Response(null, { status: 204 });
}verifyWebhookrejette tout ce qui n'est pas signé avec le secretwhsec_de votre endpoint.on conflict (submission_id) do nothingrend les nouvelles tentatives sans risque. Ikiform renvoie une livraison échouée avec la même soumission, et la deuxième insertion ne fait rien.- Une erreur de base de données lève une exception, la route répond
500et Ikiform réessaie plus tard. Vous ne perdez pas de demandes pendant un redémarrage de la base. - L'e-mail est mis en minuscules à l'arrivée, pour que le comptage des personnes distinctes fonctionne.
Étiqueter et classer
Étiqueter les nouvelles demandes
Une fois par semaine, lisez les lignes sans étiquette et donnez un thème à chacune. Les motifs gèrent les cas évidents ; lisez le reste vous-même, car les demandes intéressantes ne correspondent à aucun motif.
update feature_requests
set theme = 'invoice-export'
where theme is null
and area = 'billing'
and problem ilike any (array['%export%', '%accountant%', '%download%']);Classer les thèmes
Ceci classe les thèmes selon le nombre de demandes qui se disent bloquées, puis selon le nombre de personnes différentes qui les ont faites :
select coalesce(theme, 'untagged') as theme,
count(*) as requests,
count(distinct email) as people,
count(*) filter (where impact = 'blocking') as blocking
from feature_requests
group by 1
order by blocking desc, people desc;- Lisez en entier les textes
problemdes trois premiers thèmes avant de concevoir quoi que ce soit. - Regardez les contournements. Souvent, un petit changement supprime le plus gênant.
- Mettez le classement en regard de votre plan ; il montre la demande, pas ce qu'il est juste de construire.
Boucler la boucle
Quand un thème est livré, récupérez tous ceux qui l'ont demandé :
select distinct email
from feature_requests
where theme = 'invoice-export';Envoyez un court e-mail depuis votre outil d'e-mailing ou votre propre boîte, qui dit ce qui est sorti avec un lien. Ikiform n'envoie pas d'e-mail à la personne qui remplit le formulaire. Les e-mails de notification vont uniquement à vous et à votre équipe : il n'y a donc ni réponse automatique, ni e-mail de confirmation, ni double opt-in. Envoyez-les depuis votre outil d'e-mailing, déclenché par un webhook. C'est pareil ici : l'e-mail de lancement vient de vous, pas d'Ikiform.
Vérifiez que tout fonctionne
- Envoyez une demande avec un problème de 10 caractères. Ikiform répond
422en nommantproblem. - Envoyez une vraie demande. Elle apparaît sous Submissions et comme une ligne dans
feature_requests. - Sous Webhooks, renvoyez la livraison. La table n'a toujours qu'une ligne pour cette soumission.
- Envoyez deux fois avec le même e-mail en changeant la casse. La requête de classement compte une seule personne.
Pièges
- Un tableau de feedback public, comme Canny, ajoute le vote et une page de statut publique. Si vous voulez que les clients voient les demandes des autres, c'est le meilleur outil ; cette configuration garde les demandes privées.
- Les demandes qui contiennent plusieurs liens peuvent être notées comme spam. Vérifiez le filtre Spam chaque semaine tant que le volume est faible.
- Si vous ajoutez plus tard une option à
area, ajoutez-la d'abord à la définition. Une valeur non listée est refusée. - Stockez ce dont vous avez besoin, rien de plus. Une table de demandes avec des e-mails, ce sont des données personnelles ; indiquez-le dans votre politique de confidentialité et supprimez les lignes dont vous n'avez plus besoin.
Dépannage
| Problème | Que faire |
|---|---|
| Des lignes manquent dans la table | Ouvrez l'endpoint sous Webhooks. Un 400 signifie que le secret est faux ; un 500 avec une erreur de base de données signifie que l'insertion a échoué et qu'Ikiform réessaie. |
422 validation_failed | L'envoi ne correspond pas à la définition des champs du formulaire. error.fields nomme chaque champ et la raison. Faites correspondre le name de l'input à l'id du champ. |
| La soumission est dans le tableau de bord mais aucun e-mail ni webhook n'est arrivé | Elle a été stockée comme spam. Le spam n'envoie rien. Ouvrez-la sous le filtre Spam pour voir les raisons, et marquez-la comme non-spam pour envoyer son e-mail et ses webhooks. |
Questions
Ce que la personne essaie de faire, comment elle s'y prend aujourd'hui, quelle partie du produit est concernée, quelle importance cela a, et un e-mail. Demander le problème plutôt que la fonctionnalité vous laisse la place de trouver une meilleure solution.
Attendez-vous-y et comptez des personnes, pas des lignes. Attribuez un thème à chaque demande et classez les thèmes par e-mails distincts. Ikiform stocke chaque soumission et ne fusionne pas les répétitions.
Pas avec un simple formulaire. Un formulaire garde les demandes privées ; un tableau public comme Canny ajoute le vote. Compter les personnes distinctes par thème vous donne un équivalent privé.
Gardez l'e-mail avec chaque demande, sélectionnez tous les e-mails du thème livré et envoyez un seul message depuis votre outil d'e-mailing. Ikiform n'écrit pas lui-même aux personnes qui envoient le formulaire.
Une étape vous bloque, ou vous voulez un guide pour votre cas ? Écrivez à hello@ikiform.com.