Formulaire de feedback pour un site ou une application

Formulaire de feedback pour un site ou une application7 min de lecture

Ajouter un formulaire de signalement de bug qui capture la page, le navigateur et les étapes

Un formulaire de signalement de bug qui demande les étapes et la gravité, et laisse la page ajouter elle-même l'URL, le navigateur, le viewport et les erreurs récentes.

Preet SutharFondateur, Ikiform

Ne demandez à la personne que ce qu'elle sait : ce qui n'a pas marché, ce qu'elle a fait juste avant et à quel point ça la bloque. Laissez la page remplir le reste au moment de l'envoi : l'URL de la page, le user agent du navigateur, le viewport et les dernières erreurs JavaScript. Envoyez le tout à un backend de formulaires et transmettez chaque signalement à votre outil de tickets par webhook.

Ce qui change avec un signalement de bug

Un signalement de bug n'est utile que si vous pouvez le reproduire, et la personne qui signale connaît rarement les détails dont vous avez besoin. Demandez-lui quel navigateur elle utilise et vous obtenez « Chrome » ou « le normal ». Demandez l'URL et vous obtenez le nom de la page. Séparez donc le formulaire en deux : les questions auxquelles seule la personne peut répondre, et le contexte que la page connaît déjà.

Ce que la personne tape et ce que la page ajoute dans un signalement de bugla personne tapela page ajoute à l'envoirésuméune ligne, 8 à140 caractèresétapesce qu'elle afait justeavantgravitébloquant,majeur oumineurlien decapturefacultatif, uneURL, pas unfichierpage_urlorigine etchemin, sansparamètresuser_agentnavigateur etOSviewporttaille et ratiode pixelsrecent_errorsles cinqdernières, sanshôtesCe que la personne tape et ce que la page ajoute dans un signalement de bugla personne tapela page ajoute à l'envoirésuméune ligne, 8 à 140 caractèresétapesce qu'elle a fait juste avantgravitébloquant, majeur ou mineurlien de capturefacultatif, une URL, pas unfichierpage_urlorigine et chemin, sansparamètresuser_agentnavigateur et OSviewporttaille et ratio de pixelsrecent_errorsles cinq dernières, sans hôtes
  1. La personne écrit un résumé d'une ligne.
  2. Elle décrit ce qu'elle a fait juste avant que ça casse.
  3. Elle indique à quel point ça la bloque.
  4. Elle peut coller un lien vers une capture d'écran ou un enregistrement.
  5. À l'envoi, la page ajoute sa propre adresse sans les paramètres d'URL.
  6. Elle ajoute le user agent du navigateur.
  7. Elle ajoute la taille de la fenêtre et le ratio de pixels.
  8. Elle ajoute les dernières erreurs JavaScript vues, sans les noms d'hôte.
La ligne du haut est tout ce que voit la personne. Celle du bas, ce sont des inputs masqués, remplis au moment où elle appuie sur Envoyer.

Trois contraintes guident le code :

  • Le referrer n'est pas la page. Par défaut, les navigateurs n'envoient que votre origine sur un envoi cross-site, donc meta.referrer ne vous donnera pas le chemin. Envoyez page_url vous-même.
  • Un envoi depuis le serveur masque le navigateur. Ikiform enregistre le user agent de qui fait la requête. Depuis une server action, c'est votre serveur. Transmettez l'en-tête user-agent du visiteur dans un champ.
  • Les stack traces sont pleines de liens. Chaque frame contient l'URL d'un script, et trois liens ou plus ajoutent 2 au score de spam. Retirez les hôtes avant d'envoyer les erreurs, sinon un signalement avec un lien de capture collé peut basculer en spam.

Les champs

Aperçu

Exécute le validateur d'Ikiform dans votre navigateur. Rien n'est envoyé.

À quel point cela vous bloque-t-il ?
Les cinq derniers champs sont des inputs masqués dans le vrai formulaire. Une fois définis, Ikiform vérifie leur longueur et leur type comme pour tout autre champ.

La gravité est formulée selon son effet sur la personne, pas comme un niveau de priorité. Les gens choisissent « Je ne peux pas continuer » avec justesse ; ils choisissent « Critique » pour tout. Les étapes demandent au moins 20 caractères, ce qui transforme « ça marche pas » en une phrase exploitable.

Capturer le contexte

Le navigateur remplit les champs masqués dans le handler submit, une fois que la personne a fini de taper, pour que la liste d'erreurs inclue tout ce qui a mal tourné pendant qu'elle rédigeait le signalement.

Le formulaire envoie de façon classique ; le script ne fait que remplir les inputs masqués pendant submit, avant que le navigateur ne construise la requête. Définissez data-app-version sur l'élément <html> au build. Le navigateur envoie directement, donc le meta.user_agent d'Ikiform correspond au champ user_agent.

report-bug.html
<form id="bug" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="summary">What went wrong?</label>
  <input id="summary" name="summary" required minlength="8" maxlength="140" />
  <label for="steps">What did you do right before?</label>
  <textarea id="steps" name="steps" rows="5" required minlength="20"></textarea>
  <label for="expected">What did you expect to happen?</label>
  <textarea id="expected" name="expected" rows="3"></textarea>
  <fieldset>
    <legend>How much does it block you?</legend>
    <label><input type="radio" name="severity" value="blocker" required /> I can't continue</label>
    <label><input type="radio" name="severity" value="major" /> I found a workaround</label>
    <label><input type="radio" name="severity" value="minor" /> It's cosmetic</label>
  </fieldset>
  <label for="screenshot_url">Link to a screenshot or recording</label>
  <input id="screenshot_url" name="screenshot_url" type="url" />
  <label for="email">Email for follow-up questions</label>
  <input id="email" name="email" type="email" />
  <input type="hidden" name="page_url" />
  <input type="hidden" name="user_agent" />
  <input type="hidden" name="viewport" />
  <input type="hidden" name="app_version" />
  <input type="hidden" name="recent_errors" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send report</button>
</form>

<script>
  const recent = [];
  function remember(text) {
    recent.push(String(text).replace(/https?:\/\/[^/\s]+/g, "").slice(0, 400));
    if (recent.length > 5) recent.shift();
  }
  window.addEventListener("error", (event) => remember(`${event.message} at ${event.filename}:${event.lineno}`));
  window.addEventListener("unhandledrejection", (event) => remember(`Unhandled: ${event.reason?.stack ?? event.reason}`));

  document.getElementById("bug").addEventListener("submit", (event) => {
    const fields = event.currentTarget.elements;
    fields.page_url.value = location.origin + location.pathname;
    fields.user_agent.value = navigator.userAgent;
    fields.viewport.value = `${innerWidth}x${innerHeight} @${devicePixelRatio}x`;
    fields.app_version.value = document.documentElement.dataset.appVersion ?? "";
    fields.recent_errors.value = recent.join("\n---\n");
  });
</script>
Les versions côté serveur envoient avec une clé secrète, donc Ikiform ignore Allowed domains et sa vérification humaine. Chaque envoi vient alors de l'IP de votre serveur, et la limite Standard de 5 par minute et par visiteur compte tous vos visiteurs ensemble. Choisissez la limite de débit Relaxed ou Custom pour un formulaire que vous envoyez via un serveur, et gardez IKIFORM_SECRET_KEY dans des variables d'environnement réservées au serveur.

Le message de succès affiche l'id de la soumission. Quand la personne écrit plus tard au support, cet id retrouve le signalement en une recherche. Le modèle de signalement de bug propose une version plus courte, sans le contexte capturé.

Dans votre outil de tickets

Les signalements doivent aller là où la correction sera suivie. Ajoutez un webhook qui pointe vers un relais qui crée un ticket : summary comme titre, les étapes et le contexte comme corps, severity comme label. Le guide Linear et GitHub Issues fournit ce relais, avec vérification de signature et nouvelles tentatives. La documentation des webhooks liste chaque valeur meta que contient le payload. Placez les champs capturés dans un bloc replié à la fin du corps du ticket, pour que les étapes restent lisibles.

ChampDans le ticket
summaryTitre
steps, expectedCorps, en premier
severityUn label, pour filtrer les blocages
page_url, user_agent, viewport, app_versionUn bloc de détails sous les étapes
recent_errorsUn bloc de code, en dernier

Vérifiez que tout fonctionne

  1. Ouvrez la page dans un navigateur de bureau, lancez undefinedFunction() dans la console, puis envoyez un signalement.
  2. Ouvrez la soumission dans le tableau de bord. recent_errors contient la ReferenceError sans aucun hôte https://.
  3. user_agent affiche votre navigateur, pas node, y compris dans les versions serveur.
  4. page_url contient le chemin mais pas les paramètres d'URL.
  5. Envoyez un signalement avec des steps de 10 caractères. Ikiform répond 422 en nommant steps, et le formulaire affiche le message.

Pièges

  • L'envoi de fichiers n'est pas encore pris en charge. Un envoi avec un fichier reçoit 422 files_not_supported. Demandez un lien vers une capture d'écran, ou envoyez d'abord l'image sur votre propre stockage et soumettez son URL.
  • Chaque valeur peut faire jusqu'à 16 Ko. Cinq erreurs coupées à 400 caractères restent bien en dessous ; un dump complet de la console, non.
  • Les navigateurs Chromium figent certaines parties de la chaîne user agent, comme la version de macOS, qui vaut toujours 10_15_7. Pour le tri, utilisez le nom du navigateur et sa version majeure, pas la version de l'OS.
  • Les erreurs des scripts d'une autre origine n'affichent que Script error., sauf si ce script est servi avec des en-têtes CORS et chargé avec crossorigin.
  • Ne capturez dans le signalement ni le contenu des formulaires, ni le local storage, ni les cookies. Ils peuvent contenir des mots de passe et des tokens, que vous stockeriez en clair.

Dépannage

ProblèmeQue faire
422 validation_failedL'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.
422 files_not_supportedLe formulaire a un <input type="file"> avec un fichier choisi. L'envoi de fichiers n'est pas encore pris en charge ; retirez l'input ou demandez plutôt un lien.
Les signalements avec des liens de capture tombent en spamComptez les liens sur l'ensemble des champs. Trois ou plus augmentent le score ; avec une répétition du même signalement, il atteint le seuil. Retirez les hôtes des erreurs et marquez le signalement comme non-spam.
403 origin_not_allowed, ou tous les envois finissent en spamLe domaine de la page n'est pas dans les Allowed domains du formulaire. Ajoutez-le, plus localhost pour les tests en local. Les sous-domaines d'un domaine listé sont autorisés.

Questions

Une étape vous bloque, ou vous voulez un guide pour votre cas ? Écrivez à hello@ikiform.com.