Nous developpons votre site vitrine SPA À PARTIR DE 300€. Oui, c'est dingue. Web SPA À PARTIR DE 300€ — Oui, c'est dingue. Parlons-en →

Comment collecter les incidents de vos utilisateurs sans monter un Jira

Comment collecter les incidents de vos utilisateurs sans monter un Jira

Quand un utilisateur signale un bug, le coût n'est pas d'ouvrir le ticket : c'est la semaine d'e-mails nécessaire pour le reproduire. Monter un gestionnaire d'incidents complet range les tickets, mais ne règle pas cela. Vous verrez ici quel contexte capturer automatiquement, comment enregistrer l'écran sans bibliothèque externe et pourquoi la vidéo doit pouvoir tourner formulaire fermé. Les exemples sont en Laravel, l'une de nos spécialités, mais l'essentiel est du JavaScript de navigateur et fonctionne avec n'importe quel backend.

Le coût d'un incident n'est pas dans le ticket, il est dans sa reproduction

Pensez au cycle complet d'un bug signalé par un utilisateur. Il écrit « ça ne me laisse pas enregistrer ». Quelqu'un lui demande sur quel écran. Il répond le lendemain. On lui réclame une capture. Il envoie une photo de son moniteur prise au téléphone. On lui demande quel navigateur il utilise. Il ne le sait pas.

Trois jours et quatre courriels y sont passés, et le ticket ne dit toujours rien d'utile. Monter un gestionnaire d'incidents complet ne règle pas ça : il classe les tickets, il ne les rend pas reproductibles.

Ce qui règle le problème, c'est de capturer le contexte à l'instant même où l'utilisateur voit le bug, sans rien lui demander qu'il ne saurait pas répondre.

Le contexte technique se capture tout seul, et c'est la moitié du travail

De tout ce qu'un développeur a besoin pour reproduire quelque chose, l'utilisateur ne peut apporter qu'une partie : ce qu'il essayait de faire et ce qui s'est passé. Le reste, le navigateur le sait.

Un widget de signalement bien fait joint sans rien demander :

L'URL exacte où il se trouvait, qui règle d'un coup la question de l'écran. Le navigateur et sa version, sans que personne ait à aller le chercher dans un menu. La taille de la fenêtre, là où se cachent la moitié des bugs de mise en page. La langue de l'application, critique si le site est multilingue. Qui signale, si la session est ouverte. Et d'où il venait, ce qui est souvent l'indice.

L'utilisateur n'écrit que le message. Tout le reste part tout seul, et gratuitement.

Enregistrer l'écran ne demande plus aucune bibliothèque

Enregistrer l'écran sonne comme une fonctionnalité qui exige une dépendance lourde, et c'est pourquoi presque personne ne la propose dans un formulaire d'incident. La capture d'écran fait partie du navigateur depuis des années, et cela tient en quatre lignes :

const stream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: false });
const mime = ['video/webm;codecs=vp9', 'video/webm', 'video/mp4']
    .find(t => MediaRecorder.isTypeSupported(t)) || '';
const recorder = new MediaRecorder(stream, { mimeType: mime, videoBitsPerSecond: 2000000 });

Avec ça, l'utilisateur peut reproduire le bug devant vous au lieu de le décrire. Et une vidéo de quatre-vingt-dix secondes montrant le bug en train de se produire vaut plus que n'importe quelle description écrite par quelqu'un qui n'est pas technicien.

Il y a trois choses à cadrer et elles ne sont pas facultatives. Une durée maximale, parce que personne ne regardera sept minutes. Une limite de débit, parce que la vidéo s'accumule dans la mémoire du navigateur avant d'être envoyée et deux mégabits par seconde suffisent largement pour lire une interface. Et détecter si le navigateur en est capable : la capture d'écran exige un contexte sécurisé et n'existe pas sur mobile, donc le bouton ne doit apparaître que là où il fonctionne.

Le formulaire doit s'effacer pour que l'utilisateur reproduise le bug

Une fonctionnalité peut être complète et parfaitement testée sans que personne ne l'utilise, parce qu'elle gêne précisément au moment où l'on en a besoin. L'enregistrement d'écran en est l'exemple le plus net que je connaisse.

Si l'utilisateur clique sur « enregistrer » et que le formulaire de signalement reste par-dessus l'écran, il ne peut rien reproduire : le bug est sous la boîte de dialogue. Donc au démarrage de l'enregistrement le formulaire se ferme et laisse à sa place une petite barre avec le chronomètre et un bouton d'arrêt. L'utilisateur fait ce qu'il était en train de faire, arrête, et le formulaire se rouvre avec la vidéo déjà jointe.

Et il faut prévoir que l'utilisateur coupe depuis la barre native du navigateur, celle qui apparaît dès qu'on partage son écran :

stream.getVideoTracks()[0].addEventListener('ended', () => this.stopRecording());

Sans cette ligne, celui qui clique sur « Arrêter le partage » dans l'avertissement du navigateur se retrouve avec un enregistrement en suspens et aucun moyen de le récupérer.

Andie recommande

L'enregistrement vit dans le navigateur jusqu'à l'envoi, et c'est pour cela qu'il ne consomme rien de votre serveur pendant que l'utilisateur reproduit le bug. Pour qu'il survive à la navigation d'une application de type SPA, placez le widget dans un @persist : l'utilisateur peut ainsi aller jusqu'à l'écran du problème enregistrement en cours et l'envoyer de là.

Refuser le SVG comme capture est une décision de sécurité

Petit détail avec une vraie raison. Dans la validation de la pièce jointe, la liste des formats acceptés comprend JPG, PNG, GIF et WebP, et laisse le SVG de côté volontairement.

Un SVG est un document XML qui peut contenir des scripts. Si un jour vous servez cette pièce jointe depuis une URL publique, vous avez accepté de téléverser du contenu exécutable sur votre domaine. C'est exactement le genre de chose à laquelle on ne pense pas en écrivant la liste des formats et qui se paie plus tard.

Les pièces jointes vont sur un disque privé, et cela oblige à les servir vous-même

Par défaut, les captures et les vidéos vont dans un stockage privé, sans URL publique. C'est le bon choix, parce qu'une capture d'écran d'un utilisateur peut contenir des données de ses propres clients, et une URL devinable dans un bucket public est une fuite qui n'attend que d'arriver.

La contrepartie, c'est qu'il faut les servir à la main, avec une route protégée :

Route::get('/bugs/{report}/screenshot', [AdminController::class, 'bugScreenshot'])
    ->middleware(['web', 'auth', 'is_admin']);

Ce sont dix lignes et ce sont elles qui séparent un système de signalements d'une fuite de données. Si quelqu'un configure le disque en public « pour tester », cela ne se défait plus : les URL restent exposées.

Enregistrer n'est pas prévenir

Un incident enregistré dans une table que personne ne consulte ne sert guère plus que de ne pas l'avoir recueilli. C'est la partie qu'on repousse toujours, parce que le formulaire fonctionne déjà et que la confirmation s'affiche.

Un widget de signalement enregistre dans votre base de données et renvoie une confirmation, ce qui est exactement son travail. L'alerte et le flux de tickets sont vos décisions, et il vaut mieux les régler le jour même de l'installation : un utilisateur qui prend la peine d'enregistrer une vidéo attend de voir que quelqu'un l'a regardée.

Ce qu'il faut ajouter tient en deux choses, et elles sont petites. Une boîte de réception avec des états, même s'il n'y en a que trois : nouveau, vu, résolu. Et une alerte vers le canal que vous consultez vraiment, un courriel ou un message à un bot. Sur Crowd Legal, la boîte marque automatiquement comme vu à l'ouverture d'un signalement et efface les pièces jointes du disque à sa suppression, ce qui est le détail qui évite d'accumuler des vidéos de bugs résolus il y a un an.

Ce qui existe sur le marché et ce qui change

Ce qui se vend sous l'étiquette d'outils de remontée d'erreurs recouvre des choses qui ne se concurrencent pas : les unes écoutent l'application, les autres l'utilisateur, d'autres encore se contentent de ranger ce qui arrive. Les confondre conduit à acheter la mauvaise.

Sentry et ses équivalents capturent les erreurs tout seuls, avec la pile d'appels et tout le contexte de l'exception. C'est une catégorie différente et complémentaire : elle ne voit que ce qui casse. Un bouton qui ne fait rien, un total mal calculé ou un texte dans la mauvaise langue ne lèvent aucune exception, donc ils n'arrivent jamais jusque-là.

Marker.io, BugHerd et Usersnap sont pensés pour les cycles de relecture avec un client : annoter par-dessus la page, désigner l'élément, et pousser le signalement directement vers Jira ou Trello. Pour une agence dont les clients relisent les livrables, c'est de la valeur réelle. Le compromis : abonnement par utilisateur, un script tiers chargé sur vos pages de production et des signalements qui vivent dans un système qui n'est pas le vôtre.

Jira avec son widget vous donne le flux de travail complet, et c'est à la fois son point fort et son coût : c'est un outil de gestion de projet entier pour recueillir quatre incidents.

La différence, quand on le résout à l'intérieur de l'application, c'est que le signalement est une ligne de votre base de données, avec une relation polymorphe vers l'utilisateur qui l'a envoyé, donc vous pouvez le croiser avec ce que vous savez déjà de lui. Pas de script externe, pas de coût par utilisateur, et le widget a l'apparence de votre produit. En échange, la boîte de réception et les alertes, c'est vous qui les écrivez.

Et si vous ne travaillez pas avec Laravel

Les critères sont les mêmes et servent à évaluer n'importe quelle solution :

  • Qu'elle capture le contexte sans rien demander. URL, navigateur, taille de fenêtre et identité. Si vous les demandez à l'utilisateur, il ne vous les donnera pas correctement.
  • Qu'elle permette d'enregistrer l'écran et que le formulaire s'efface pendant l'enregistrement.
  • Que les pièces jointes aillent dans un stockage privé par défaut.
  • Qu'elle refuse les formats exécutables en guise d'image.
  • Et qu'il y ait quelqu'un qui regarde la boîte de réception. C'est la partie qu'aucun outil ne fournit.

Où se trouve le code

Le paquet est sur Packagist, le code sur GitHub et la documentation du paquet recense toutes les options. Il est en MIT, sans dépendances npm et sans requêtes vers des tiers.

Sur Crowd Legal, il n'est présent que derrière l'authentification, sous forme d'onglet latéral, avec la boîte de réception d'administration et les routes protégées que décrit cet article.

Si vous avez un produit en production et que les incidents vous arrivent par WhatsApp, cela se monte en une après-midi et change la relation avec vos utilisateurs. Nous le travaillons en applications web et en SaaS sur mesure, et si vous nous racontez comment ils vous parviennent aujourd'hui, nous vous dirons quoi mettre en place.

Écrit par
Edu Lazaro
Edu Lazaro
Founder & Lead Developer en AndorraDev

Développeur full-stack avec plus de 15 ans d'expérience en Laravel, React, Node.js et architectures cloud. J'aide les entreprises en Andorre à construire leur présence digitale.

Partner de diseño · ionospace.
Besoin d'aide? ×
Andie by AndorraDev
Assistant IA + équipe humaine
Assistant IA d'AndorraDev
Andie
Bonjour! Je suis Andie, l'assistant IA d'AndorraDev. Comment puis-je vous aider? Si vous souhaitez parler avec Edu, il suffit de le demander.
17:31