Communitygithub.com

constancetanahrefs/webinar-analyzer

Une spécification portable de compétence pour construire un tableau de bord d'analyse de webinaires neutre en termes de plateforme : passerelle d'anonymisation, mappage de colonnes, analyses par webinaire et inter-webinaires.

Qu'est-ce que webinar-analyzer ?

Webinar Analyzer est une compétence spécifiée de manière abstraite (stack-neutral) qui permet de transformer des exportations brutes de webinaires en deux types d'analyses : par webinaire (qui est venu, combien de temps ils sont restés, quand ils sont partis) et inter-webinaires (croissance de l'assistance, créneaux horaires et formats performants, fidélisation des participants). L'outil exige une conversation d'accueil structurée en cinq étapes : identification des plateformes (Zoom, Teams, Livestorm, etc.), demande d'un vrai fichier d'export, passage par une passerelle de confidentialité obligatoire qui rejette toute donnée personnelle non anonymisée, mappage des colonnes au schéma canonique, et rapport de disponibilité des fonctionnalités. Le schéma canonique définit quatre entités principales : `webinar` (session), `attendee_session` (participation par personne), `feedback_response` (réponses aux enquêtes), et `replay_stats` (statistiques de rediffusion). La plateforme est neutre : la compétence spécifie les contrats de données, les règles de validation, les calculs et la sémantique des graphiques, et peut être implémentée dans n'importe quelle pile (Flask, FastAPI, Streamlit, notebook, outil BI). Une référence d'implémentation existe en Flask + PostgreSQL + ApexCharts.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add constancetanahrefs/webinar-analyzer

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Analyseur de Webinaires

Un outil qui transforme les exportations brutes de webinaires en deux types de réponses :

  1. Par webinaire — qui est venu, combien de temps ils sont restés, quand ils sont partis, qui ils étaient, ce qu'ils ont dit.
  2. Inter-webinaires — l'assistance augmente-t-elle, quel créneau et quel format fonctionnent, qui revient, et quels éloges et plaintes se répètent.

Cette compétence est neutre en termes de pile. Elle spécifie des contrats de données, des règles de validation, des calculs et une sémantique de graphiques. Implémentez-la dans la pile web de votre choix (Flask/Django/FastAPI + Postgres + n'importe quelle bibliothèque de graphiques ; Streamlit ; un notebook ; un outil BI). L'implémentation de référence à partir de laquelle ces instructions ont été extraites est une application Flask + PostgreSQL + ApexCharts.


Avant de construire quoi que ce soit : la conversation d'accueil

Ne partez pas du principe que c'est Zoom. Ne partez pas du principe que c'est YouTube. Le plus grand échec de cet outil est de coder en dur le format d'exportation d'une seule plateforme. L'utilisateur peut organiser des webinaires sur Teams, GoToWebinar, Livestorm, Demio, Webex, Hopin, Riverside, StreamYard, Crowdcast, BigMarker ou une pile personnalisée, et peut héberger les rediffusions sur Vimeo, Wistia, son propre CDN, ou nulle part.

Exécutez cette séquence avant d'écrire du code :

Étape 1 — Demandez quelles plateformes sont en jeu

Demandez, sous forme de question à choix multiples courte :

  • Sur quelle plateforme organisez-vous des webinaires en direct ? (Zoom Webinars / Zoom Meetings / Microsoft Teams / GoToWebinar / Livestorm / Demio / Webex / Hopin / BigMarker / Crowdcast / autre)
  • Où se trouvent les enquêtes post-webinaire ? (intégrées à la plateforme de webinaire / Typeform / Google Forms / SurveyMonkey / Hubspot / aucune)
  • Où se trouvent les rediffusions, le cas échéant ? (YouTube / Vimeo / Wistia / auto-hébergé / page d'atterrissage avec accès restreint / pas de rediffusions)
  • Disposez-vous de données d'inscription distinctes des données de présence ? (un seul export combiné / deux exports séparés / inscription uniquement / présence uniquement)

Étape 2 — Demandez un véritable export, avant de concevoir quoi que ce soit

Dites clairement : « Téléchargez un véritable export de chaque source — participants, enquête, rediffusion — avec les données personnelles déjà supprimées. Je lirai les en-têtes de colonnes réels au lieu de deviner, et je vous dirai quelles parties du tableau de bord vos données peuvent et ne peuvent pas prendre en charge. »

Insistez là-dessus. Un seul fichier réel supprime toutes les hypothèses. Si l'utilisateur ne peut pas partager de données réelles, demandez-lui de coller la ligne d'en-tête plus 2 à 3 lignes entièrement fabriquées.

Étape 3 — Exécutez le contrôle de confidentialité sur le fichier téléchargé

Voir Contrôle de confidentialité. Rejetez le fichier s'il contient des données personnelles non anonymisées. Ne passez pas au mappage tant qu'un fichier propre n'est pas fourni.

Étape 4 — Mappez leurs colonnes au schéma canonique

Montrez à l'utilisateur un tableau de mappage explicite (leur colonne → champ canonique → ce qu'il débloque), et nommez ce qui manque. Voir Exigences de champs et references/platform-exports.md.

Étape 5 — Dites-leur quels graphiques ils obtiennent

Affichez un rapport de disponibilité des fonctionnalités avant de construire :

✅ Disponible avec vos données
   Distribution du temps de visionnage, chronologie des spectateurs simultanés, détection des abandons,
   entonnoir de présence, croissance mois par mois, nouveaux vs retours.

⚠️  Partiellement disponible
   Données démographiques — vous avez le Pays mais pas le Titre de poste, donc le donut de
   séniorité sera masqué.

❌ Non disponible
   Analyses des rediffusions — pas d'export de rediffusion. L'onglet Rediffusions sera masqué
   jusqu'à ce que vous en ajoutiez un (ou vous pouvez saisir les chiffres manuellement via le modèle CSV).

Ne construisez jamais un graphique dont les données d'entrée n'existent pas. Masquez tout le panneau et affichez une explication d'une ligne sur les données qui l'activeraient.


Contrôle de confidentialité (OBLIGATOIRE)

Chaque fichier téléchargé passe un contrôle d'anonymisation avant l'analyse, avant le stockage, avant l'analyse proprement dite. Si des données personnelles sont trouvées, rejetez l'intégralité du fichier, nommez les colonnes et numéros de ligne incriminés, et expliquez comment les anonymiser. N'importez jamais partiellement. N'anonymisez jamais automatiquement en silence.

Ce qui est considéré comme des données personnelles

CatégorieDétection
Adresses e-mail[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} dans n'importe quelle cellule
Numéros de téléphone(?:\+?\d[\s\-\(\)\.]{0,2}){7,15} avec ≥7 chiffres, à l'exclusion des horodatages/ID purs
Adresses postalesCellule correspondant à des mots-clés de type rue (`street
Codes postaux / ZIP\b\d{5}(-\d{4})?\b ou [A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2} lorsque le nom de colonne suggère un lieu
Adresses IPLittéral IPv4/IPv6
Identifiants gouvernementaux / de paiement\b\d{3}-\d{2}-\d{4}\b (forme SSN), \b(?:\d[ -]*?){13,16}\b réussissant un contrôle Luhn
Noms de colonnes suspectsEn-tête correspondant à `email

Règles

  1. Analyse d'en-tête d'abord. Toute colonne dont le nom correspond à la liste suspecte est signalée même si les cellules échantillonnées semblent vides — une colonne vide aujourd'hui peut être remplie demain.
  2. Analysez chaque cellule de chaque ligne. Pas un échantillon. Les fichiers sont petits (des milliers de lignes) ; une analyse complète est peu coûteuse et une analyse par échantillon donne une fausse assurance.
  3. Les réponses d'enquête en texte libre sont également analysées. Les gens tapent « envoyez-moi un e-mail à [email protected] » dans les boîtes de commentaires. C'est la fuite la plus souvent manquée.
  4. Rejetez dès la première catégorie trouvée, mais signalez-les toutes. Terminez l'analyse et présentez tous les problèmes à la fois afin que l'utilisateur corrige le fichier en une seule fois.
  5. N'écrivez jamais un fichier rejeté sur le disque ou dans la base de données. Conservez-le en mémoire, rejetez-le, jetez-le.
  6. Enregistrez le rejet sans les valeurs incriminées. Enregistrez uniquement les noms de colonnes et les numéros de ligne — jamais l'e-mail ou le numéro de téléphone détecté lui-même.

Identifiants autorisés (ceux-ci NE sont PAS des rejets)

  • Un ID de personne pseudo-anonyme stable — un hachage, un UUID ou un entier séquentiel cohérent entre les fichiers. Ceci est obligatoire pour l'analyse inter-webinaires (voir ci-dessous).
  • Noms de pays / régions, noms d'organisations, titres de poste, niveaux de séniorité.
  • Horodatages, durées, ID de webinaires, chaînes de sujets.

Modèle de message de rejet

❌ Téléchargement rejeté — données personnelles détectées dans attendees_march.csv

  Colonne "Email"            → 412 adresses e-mail (lignes 2–413)
  Colonne "Contact Number"   → 88 numéros de téléphone (lignes 2, 5, 9, …)
  Colonne "Que pouvons-nous améliorer ?" → 3 adresses e-mail dans du texte libre
                                   (lignes 47, 112, 288)

Rien n'a été importé et le fichier a été supprimé.

Pour corriger :
  1. Remplacez la colonne Email par un ID pseudo-anonyme stable — par exemple un
     hachage SHA-256 de l'e-mail en minuscules, tronqué à 16 caractères.
     Utilisez la MÊME méthode de hachage pour chaque fichier afin que la même personne
     soit reconnaissable d'un webinaire à l'autre.
  2. Supprimez entièrement la colonne Contact Number — elle n'est jamais utilisée.
  3. Rédigez les adresses e-mail dans les réponses en texte libre, en conservant
     le reste du commentaire.

Re-téléchargez une fois anonymisé. Voir references/anonymisation.md pour un script
prêt à l'emploi.

Pourquoi un ID pseudo-anonyme stable est négociable

La moitié de la valeur de cet outil réside dans l'analyse inter-webinaires : nouveaux vs participants de retour, cohortes de rétention, inscrits récurrents, taux de présence par personne. Tout cela nécessite de reconnaître la même personne à travers les fichiers sans savoir qui elle est. Dites-le clairement à l'utilisateur lors de l'accueil — s'ils anonymisent les e-mails en blancs ou en valeurs aléatoires par fichier, chaque graphique inter-webinaires devient silencieusement dénué de sens.

Recommandé : person_id = sha256(lower(strip(email)) + fixed_salt)[:16], avec le sel stocké en dehors de l'ensemble de données. references/anonymisation.md contient un script prêt à l'emploi.


Exigences de champs

Le tableau de bord fonctionne sur un schéma canonique. Les colonnes d'exportation de l'utilisateur sont mappées sur celui-ci. Tout ce que le mappage ne peut pas remplir est une fonctionnalité qui est masquée.

Entité canonique : webinar (une ligne par session)

ChampObligatoire ?TypeDébloqueColonne source typique
external_idObligatoiretexte, uniqueTout — la clé de jointure entre les fichiers participants/enquête/rediffusionID Webinaire, ID Réunion, ID Événement, ID Session
topicObligatoiretexteTout étiquetage ; regroupement de campagne des rediffusionsSujet, Titre, Nom de l'événement
start_timeObligatoirehorodatageChaque graphique temporel ; mois par mois ; heure de la journée ; la chronologie de concurrenceHeure de début réelle, Début, Date
duration_minutesFortement recommandéintAxe x de la chronologie de concurrence ; % de session regardéeDurée réelle, Durée
num_registrantsRecommandéintEntonnoir, taux de présence (peut être dérivé en comptant les lignes)# Inscrits, Inscrit
unique_viewersRecommandéintGraphique de l'heure de la journée ; portée principale (dérivable)Spectateurs uniques, Participants
max_concurrentFacultatifintStatistique de pic d'audienceVues simultanées maximales

Règle de fuseau horaire : décidez une fois si les horodatages stockés sont en UTC ou dans un fuseau local fixe, écrivez-le dans le commentaire du schéma, et ne convertissez jamais ad hoc. Le regroupement mensuel lit directement ce champ. Fournissez un mécanisme de remplacement manuel du mois (voir Remplacements de mois) pour les sessions qui se déroulent juste après minuit local pour un public dans un autre fuseau horaire.

Entité canonique : attendee_session (une ligne par personne par connexion)

Une personne qui se déconnecte et se reconnecte produit plusieurs lignes. Ne dédupliquez jamais à l'ingestion — dédupliquez à l'analyse, délibérément.

ChampObligatoire ?TypeDébloqueColonne source typique
webinar_idObligatoireFKTout—
person_idObligatoire (pseudo-anonyme)texteNouveaux vs retours, rétention, inscrits récurrents, déduplication par personneEmail haché, ID participant
attendedObligatoireboolRépartition présence/absence, entonnoir, taux de présencePrésent (Oui/Non)
is_registrantRecommandéboolCohorte d'absents ; entonnoirdérivé de la présence d'une heure d'inscription
join_timeRecommandéhorodatageChronologie de concurrence, détection d'abandonsHeure de connexion
leave_timeRecommandéhorodatageChronologie de concurrence, détection d'abandonsHeure de déconnexion
minutesRecommandéintHistogramme du temps de visionnage, temps de visionnage moyenTemps passé (minutes)
country / regionFacultatiftexteDonut géographique, analyse temporelle régionalePays/Région
organizationFacultatiftexteVue au niveau du compteOrganisation, Entreprise
job_titleFacultatiftexteDonut de séniorité (dérivé)Titre de poste, Titre, Rôle
source_nameFacultatiftexteDonut du canal d'acquisitionNom de la source, Source UTM, Référent
registration_timeFacultatifhorodatageAnalyse de la courbe d'inscriptionHeure d'inscription
custom_answersFacultatifJSONUn donut par question d'inscriptionToute colonne non reconnue

Règle des colonnes non reconnues : toute colonne dans le fichier participant qui n'est pas l'un des champs connus ci-dessus est traitée comme une question d'enquête d'inscription et stockée dans custom_answers sous forme {question: answer}. Chacune de ces questions rend automatiquement son propre donut. C'est ce qui rend l'outil fonctionnel sur des plateformes que vous n'avez jamais vues.

Champ dérivé — seniority : regroupez job_title par mot-clé en C-Level / Fondateur (ceo, cto, cfo, cmo, coo, chief, founder, owner, president), VP / Directeur (vp, vice president, head of, director), Manager / Lead (manager, lead, principal), IC Senior (senior, sr.), Junior (junior, jr., intern, associate, assistant), sinon Contributeur Individuel. Masquez entièrement le graphique de séniorité lorsqu'aucune ligne n'a de titre de poste.

Entité canonique : feedback_response (une ligne par soumission d'enquête)

ChampObligatoire ?TypeDébloqueColonne source typique
webinar_idObligatoireFKJoindre les retours à la sessionID Réunion/Webinaire
person_idFacultatif (pseudo-anonyme)texteLier les retours au comportement de présenceAdresse e-mail hachée
submitted_atFacultatifhorodatageOrdre, récenceDate et heure de soumission
scoreRecommandéint 1–5Distribution de la satisfaction + moyennes« Dans quelle mesure avez-vous trouvé… »
liked_textRecommandétexteRegroupement de thèmes d'éloges« Qu'avez-vous aimé… »
improve_textRecommandétexteRegroupement de thèmes de préoccupations« Que pouvons-nous améliorer… »
other_answersFacultatifJSONTout le reste, textuellementcolonnes de questions restantes

Détection de colonne : trouvez les colonnes de score / like / amélioration par correspondance de mots-clés dans l'en-tête (useful/rate/score ; like ; improve), insensible à la casse, la première correspondance l'emporte. Montrez le mappage détecté à l'utilisateur et laissez-le le corriger — le libellé des questions d'enquête diffère d'une entreprise à l'autre.

Si l'enquête se trouve en dehors de la plateforme de webinaires (Typeform, Google Forms), elle ne portera pas d'ID de webinaire. Demandez alors à l'utilisateur soit d'ajouter un champ caché portant l'ID du webinaire, soit de sélectionner le webinaire cible dans l'interface utilisateur lors du téléchargement.

Entité canonique : replay_stats (une ligne par webinaire)

Les rediffusions sont les données les plus variables d'une plateforme à l'autre. Prenez en charge trois chemins d'ingestion, dans cet ordre de préférence :

  1. Connecteur API vers l'hôte de rediffusion (API YouTube Data/Analytics, Vimeo, Wistia) — uniquement si l'utilisateur en possède un et fournit des identifiants.
  2. Export CSV natif des analyses de l'hôte de rediffusion, mappé aux champs canoniques.
  3. Modèle CSV manuel — toujours disponible, toujours la solution de repli. Fournissez un modèle téléchargeable avec une ligne d'en-tête, un bloc de commentaires expliquant chaque métrique, et une ligne d'exemple.
ChampObligatoire ?TypeDébloque
webinar_idObligatoireclé de jointureTout ce qui concerne les rediffusions
video_id / video_urlFacultatiftexteLien profond vers la vidéo hébergée ; synchronisation API
views_day1FacultatifintGraphique de la demande précoce
views_day7FacultatifintGraphique de la demande soutenue
total_view_hoursFacultatifnumériqueGraphique de la consommation totale des rediffusions
avg_view_duration_secFacultatifintGraphique de l'engagement des rediffusions
avg_view_percentageFacultatifnumériqueGraphique de rétention des rediffusions
likes, comments, shares, subscribers_gainedFacultatifintStatistiques de réaction

Chaque champ de rediffusion est facultatif. Stockez NULL pour les blancs, jamais 0 — une métrique non mesurée et une métrique mesurée

…

[tronqué pour la traduction]

Skills associés