Webinar Analyzer
生のウェビナーエクスポートデータを2種類のインサイトに変換するツール:
- 個別ウェビナー — 誰が来たか、どのくらい滞在したか、いつ退出したか、誰だったか、何を言ったか。
- 全ウェビナー横断 — 参加者は増加しているか、どの時間帯と形式が効果的か、誰がリピート参加しているか、称賛と苦情のパターンは何か。
このスキルはスタックに依存しません。データ契約、検証ルール、計算、チャートのセマンティクスを定義します。お好みのWebスタック(Flask/Django/FastAPI + Postgres + 任意のチャートライブラリ、Streamlit、ノートブック、BIツール)で実装してください。これらの指示が抽出されたリファレンス実装は、Flask + PostgreSQL + ApexChartsアプリです。
構築前に:導入対話
Zoomを前提にしないでください。YouTubeも前提にしないでください。 このツールの最大の失敗要因は、1つのプラットフォームのエクスポート形式にハードコーディングすることです。ユーザーはTeams、GoToWebinar、Livestorm、Demio、Webex、Hopin、Riverside、StreamYard、Crowdcast、BigMarker、またはカスタムスタックでウェビナーを運営している可能性があり、リプレイはVimeo、Wistia、自社CDNでホストしているか、まったくホストしていないかもしれません。
コードを書く前にこのシーケンスを実行してください:
ステップ 1 — 使用中のプラットフォームを尋ねる
簡潔な複数選択質問として尋ねます:
- ライブウェビナーをどのプラットフォームで運営していますか? (Zoom Webinars / Zoom Meetings / Microsoft Teams / GoToWebinar / Livestorm / Demio / Webex / Hopin / BigMarker / Crowdcast / その他)
- ウェビナー後のアンケートはどこにありますか? (ウェビナープラットフォーム内蔵 / Typeform / Google Forms / SurveyMonkey / Hubspot / なし)
- リプレイはどこにありますか?(ある場合) (YouTube / Vimeo / Wistia / 自社ホスティング / ゲート付きランディングページ / リプレイなし)
- 登録データは出席データとは別にありますか? (1つの結合エクスポート / 2つの別々のエクスポート / 登録のみ / 出席のみ)
ステップ 2 — デザイン前に、実際のエクスポートを1つ要求する
簡潔に伝えてください: 「各ソース(出席者、アンケート、リプレイ)から1つずつ、実際のエクスポートファイルをアップロードしてください。個人データは削除済みでお願いします。実際のカラムヘッダーを読んで推測を排除し、お客様のデータでダッシュボードのどの部分がサポート可能かを伝えます。」
これを主張してください。実際のファイル1つで全ての前提がなくなります。ユーザーが実際のデータを共有できない場合は、ヘッダー行と完全に架空のデータ行を2~3行貼り付けるよう依頼してください。
ステップ 3 — アップロードされたファイルにプライバシーゲートを実行する
プライバシーゲート を参照してください。未スクラブの個人データが含まれている場合はファイルを拒否してください。クリーンなファイルが提供されるまでマッピングに進まないでください。
ステップ 4 — ユーザーのカラムを正規スキーマにマッピングする
ユーザーに明示的なマッピングテーブル(ユーザーのカラム → 正規フィールド → 有効になる機能)を表示し、不足しているものを明確にしてください。フィールド要件 および references/platform-exports.md を参照してください。
ステップ 5 — どのチャートが利用可能か伝える
構築前に機能可用性レポートを出力します:
✅ お客様のデータで利用可能
視聴時間分布、同時視聴者タイムライン、離脱検出、
出席ファネル、前月比成長、新規 vs リピーター。
⚠️ 一部利用可能
デモグラフィック — 国はありますが役職がないため、
役職レベルのドーナツチャートは非表示になります。
❌ 利用不可
リプレイ分析 — リプレイエクスポートがありません。リプレイタブは
追加されるまで非表示になります(またはCSVテンプレートを使用して手動で数字を入力できます)。
入力データが存在しないチャートを構築しないでください。パネル全体を非表示にし、どのデータがあれば表示されるかの1行の説明を表示してください。
プライバシーゲート(必須)
アップロードされたすべてのファイルは、解析前、保存前、分析前にスクラビングチェックを通過します。個人データが見つかった場合、ファイル全体を拒否し、問題のカラム名と行番号を特定し、スクラブ方法を説明します。部分インポートは行わないでください。自動的に匿名化することもありません。
個人データと見なされるもの
| カテゴリ | 検出方法 |
|---|---|
| メールアドレス | 任意のセルで [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} にマッチ |
| 電話番号 | 7桁以上、純粋なタイムスタンプ/IDを除く (?:\+?\d[\s\-\(\)]{0,2}){7,15} にマッチ |
| 住所 | 通り系キーワード(`street |
| 郵便番号 / ZIP | \b\d{5}(-\d{4})?\b または [A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2} で、カラム名が場所を示唆する場合 |
| IPアドレス | IPv4/IPv6リテラル |
| 政府/支払いID | \b\d{3}-\d{2}-\d{4}\b(SSN形式)、Luhnチェックを通過する \b(?:\d[ -]*?){13,16}\b |
| 疑わしいカラム名 | ヘッダーが `email |
ルール
- 最初にヘッダースキャン。 名前が疑わしいリストに一致するカラムは、サンプリングしたセルが空に見えてもフラグ付けされます。今日空のカラムも明日にはデータが入力される可能性があります。
- すべての行、すべてのセルをスキャン。 サンプリングではありません。ファイルは小規模(数千行)で、全スキャンは低コストであり、サンプルスキャンは誤った安心感を与えます。
- 自由記述のアンケート回答もスキャン。 人々はフィードバックボックスに「[email protected] にメールしてください」と入力します。これが最も見落とされやすい漏洩経路です。
- 最初に見つかったカテゴリで拒否するが、すべて報告する。 スキャンを完了し、すべての問題を一度に提示して、ユーザーが1回のパスでファイルを修正できるようにします。
- 拒否されたファイルをディスクやデータベースに書き込まない。 メモリ上に保持し、拒否後破棄します。
- 拒否はログに記録するが、問題の値は記録しない。 カラム名と行番号のみをログに記録します。検出されたメールや電話番号自体は記録しません。
許可される識別子(これらは拒否されません)
- 安定した仮名の個人ID — ファイル間で一貫性のあるハッシュ、UUID、または連続整数。これはクロスウェビナー分析に必須です(下記参照)。
- 国/地域名、組織名、役職、役職レベル。
- タイムスタンプ、時間、ウェビナーID、トピック文字列。
拒否メッセージテンプレート
❌ アップロード拒否 — attendees_march.csv に個人データが検出されました
カラム「Email」 → 412件のメールアドレス(行2〜413)
カラム「Contact Number」→ 88件の電話番号(行2、5、9、…)
カラム「What can we improve?」 → 自由記述内に3件のメールアドレス
(行47、112、288)
データはインポートされず、ファイルは破棄されました。
修正方法:
1. Emailカラムを安定した仮名IDに置き換えてください。例:
小文字化したメールのSHA-256ハッシュを16文字に切り詰めたもの。
すべてのファイルで**同じ**ハッシュ方式を使用し、同じ個人が
ウェビナー間で認識できるようにしてください。
2. Contact Numberカラムは完全に削除してください。使用されません。
3. 自由記述回答内のメールアドレスを編集し、コメントの残りの部分は
保持してください。
スクラブ後、再アップロードしてください。 references/anonymisation.md に
すぐに使えるスクラビングスクリプトがあります。
安定した仮名IDが必須である理由
このツールの価値の半分はクロスウェビナー分析にあります:新規 vs リピーター、定着コホート、リピート登録者、個人ごとの参加率。これらすべては、ファイル間で同じ個人を認識する必要がありますが、誰かは知る必要はありません。導入時にこれをユーザーに明確に伝えてください。メールを空白やファイルごとにランダムな値にスクラブすると、すべてのクロスウェビナーチャートが意味をなさなくなります。
推奨:person_id = sha256(lower(strip(email)) + fixed_salt)[:16]、ソルトはデータセットの外部に保存。 references/anonymisation.md にドロップインスクリプトがあります。
フィールド要件
ダッシュボードは正規スキーマで動作します。ユーザーのエクスポートカラムはマッピングされます。マッピングで埋められないものは、非表示になる機能です。
正規エンティティ:webinar(セッションごとに1行)
| フィールド | 必須? | タイプ | 有効になる機能 | 典型的なソースカラム |
|---|---|---|---|---|
external_id | 必須 | テキスト、一意 | すべて — 出席者/アンケート/リプレイファイル間の結合キー | Webinar ID, Meeting ID, Event ID, Session ID |
topic | 必須 | テキスト | すべてのラベリング、キャンペーングループ化(再放送) | Topic, Title, Event name |
start_time | 必須 | タイムスタンプ | すべての時間ベースチャート、前月比、時間帯、同時視聴タイムライン | Actual Start Time, Start, Date |
duration_minutes | 強く推奨 | 整数 | 同時視聴タイムラインx軸、視聴割合 | Actual Duration, Duration |
num_registrants | 推奨 | 整数 | ファネル、参加率(行数をカウントして導出可能) | # Registrants, Registered |
unique_viewers | 推奨 | 整数 | 時間帯チャート、リーチ指標(導出可能) | Unique Viewers, Attendees |
max_concurrent | オプション | 整数 | ピーク視聴者数統計 | Max Concurrent Views |
タイムゾーンルール: 保存するタイムスタンプがUTCか固定ローカルタイムかを一度決定し、スキーマコメントに記述し、アドホックに変換しないでください。月単位のバケットはこのフィールドから直接読み取ります。別のタイムゾーンの視聴者向けに現地の深夜直後に実行されるセッションのために、手動の月オーバーライドメカニズムを提供してください(月オーバーライド を参照)。
正規エンティティ:attendee_session(参加ごとに1人1行)
ドロップして再接続する人は複数行を生成します。取り込み時に重複排除しないでください。分析時に意図的に重複排除します。
| フィールド | 必須? | タイプ | 有効になる機能 | 典型的なソースカラム |
|---|---|---|---|---|
webinar_id | 必須 | 外部キー | すべて | — |
person_id | 必須(仮名) | テキスト | 新規 vs リピーター、定着、リピート登録者、個人ごとの重複排除 | Hashed Email, Attendee ID |
attended | 必須 | ブール | 出席/欠席分割、ファネル、参加率 | Attended (Yes/No) |
is_registrant | 推奨 | ブール | 欠席コホート、ファネル | Registration Time の有無から導出 |
join_time | 推奨 | タイムスタンプ | 同時視聴タイムライン、離脱検出 | Join Time |
leave_time | 推奨 | タイムスタンプ | 同時視聴タイムライン、離脱検出 | Leave Time |
minutes | 推奨 | 整数 | 視聴時間ヒストグラム、平均視聴時間 | Time in Session (minutes) |
country / region | オプション | テキスト | 地域ドーナツ、地域別時間分析 | Country/Region |
organization | オプション | テキスト | アカウント別ビュー | Organization, Company |
job_title | オプション | テキスト | 役職レベルドーナツ(導出) | Job Title, Title, Role |
source_name | オプション | テキスト | 獲得チャネルドーナツ | Source Name, UTM source, Referrer |
registration_time | オプション | タイムスタンプ | サインアップ曲線分析 | Registration Time |
custom_answers | オプション | JSON | 登録質問ごとに1つのドーナツ | 未認識のカラム |
未認識カラムルール: 出席者ファイル内で上記の既知のフィールドではないカラムは、登録アンケート質問として扱われ、custom_answers に {質問: 回答} として保存されます。各質問は自動的に独自のドーナツチャートをレンダリングします。これにより、これまで見たことのないプラットフォームでもツールが機能します。
導出フィールド — seniority: job_title をキーワードでバケット化:C-Level / 創業者(ceo, cto, cfo, cmo, coo, chief, founder, owner, president)、VP / ディレクター(vp, vice president, head of, director)、マネージャー / リード(manager, lead, principal)、シニアIC(senior, sr.)、ジュニア(junior, jr., intern, associate, assistant)、それ以外は 個人貢献者。役職を持つ行がない場合、役職レベルのチャート全体を非表示にします。
正規エンティティ:feedback_response(アンケート送信ごとに1行)
| フィールド | 必須? | タイプ | 有効になる機能 | 典型的なソースカラム |
|---|---|---|---|---|
webinar_id | 必須 | 外部キー | フィードバックをセッションに結合 | Meeting/Webinar ID |
person_id | オプション(仮名) | テキスト | フィードバックを出席行動にリンク | Hashed Email Address |
submitted_at | オプション | タイムスタンプ | 並び順、新しさ | Submitted Date and Time |
score | 推奨 | 整数 1~5 | 満足度分布 + 平均 | 「このセミナーは役に立ちましたか…」 |
liked_text | 推奨 | テキスト | 称賛テーマクラスタリング | 「良かった点は…」 |
improve_text | 推奨 | テキスト | 懸念テーマクラスタリング | 「改善点は…」 |
other_answers | オプション | JSON | その他すべて、原文のまま | 残りの質問カラム |
カラム検出: ヘッダーのキーワードマッチ(useful/rate/score、like、improve)でスコア/ liked / improveカラムを見つけます。大文字小文字を区別せず、最初のマッチを優先します。検出されたマッピングをユーザーに表示し、修正できるようにします。アンケートの質問の文言は企業ごとに異なります。
アンケートがウェビナープラットフォーム外にある場合(Typeform、Google Forms)、ウェビナーIDは含まれません。その場合、ユーザーにウェビナーIDを運ぶ隠しフィールドを追加するか、アップロード時にUIでターゲットウェビナーを選択するよう要求します。
正規エンティティ:replay_stats(ウェビナーごとに1行)
リプレイデータはすべてのデータの中で最もプラットフォームによって異なります。3つの取り込みパスをサポートします。優先順位は以下の通り:
- リプレイホストへのAPIコネクタ(YouTube Data/Analytics API、Vimeo、Wistia) — ユーザーが持っていて認証情報を提供する場合のみ。
- リプレイホストからのネイティブ分析CSVエクスポート — 正規フィールドにマッピング。
- 手動テンプレートCSV — 常に利用可能で、常にフォールバック。ヘッダー行、各メトリクスの説明ブロック、1つのサンプル行を含むダウンロード可能なテンプレートを提供します。
| フィールド | 必須? | タイプ | 有効になる機能 |
|---|---|---|---|
webinar_id | 必須 | 結合キー | リプレイ関連のすべて |
video_id / video_url | オプション | テキスト | ホストされているビデオへのディープリンク、API同期 |
views_day1 | オプション | 整数 | 初日需要チャート |
views_day7 | オプション | 整数 | 持続需要チャート |
total_view_hours | オプション | 数値 | 総リプレイ消費チャート |
avg_view_duration_sec | オプション | 整数 | リプレイエンゲージメントチャート |
avg_view_percentage | オプション | 数値 | リプレイ維持率チャート |
likes、comments、shares、subscribers_gained | オプション | 整数 | リアクション統計 |
すべてのリプレイフィールドはオプションです。空白は NULL で保存し、0 では保存しないでください。測定されていないメトリクスと測定値が0のメトリクスは異なります。
計算とセマンティクス
1. 視聴時間分布(ヒストグラム)
- 必要なデータ:
attendee_session.minutes+attended=true - 計算: 出席者を分単位のバケットにビン分割:
<5、5–10、10–20、20–30、30–45、45–60、60+。各バケットの人数をカウント。 - チャートタイプ: 棒グラフ(水平または垂直)。
- 既知のすべてのバケットを表示します。値がゼロでも。
- NaN/Nullルール:
minutesがNULLの行は欠落としてカウントし、グラフの上のアノテーションに表示。
2. 同時視聴者タイムライン
- 必要なデータ:
attendee_session.join_time+leave_time(両方) +webinar.duration_minutes - 計算: 結合/離脱イベントをソートし、累積同時視聴者数を計算。X軸:ウェビナー経過時間(分)。Y軸:同時視聴者数。
- 欠落データのフォールバック: 正確なjoin/leave_timeがないが
minutesがある場合、join_timeをstart_time、leave_timeをstart_time + minutesと仮定。この段階でこの推定値をユーザーに表示します。 - チャートタイプ: エリアグラフ。
3. 離脱検出
- 必要なデータ: 結合/離脱時間、または
minutes、またはleave_time。最も正確な入手可能なものを使用。 - 計算: 各参加者の滞在時間を計算し、
duration_minutesの半分未満のものを「早期離脱」とマーク。これらの割合を報告。 - オプションの強化: 早期離脱者とその他の人の間で
country、source、job_titleを比較(クラスタリング用)。
4. 出席ファネル
- 必要なデータ:
webinar.num_registrantsまたはattendee_session.is_registrant、attendee_session.attended - 段階:
- 登録者 → 出席者→ 参加した → (オプション)___分以上滞在した
- チャートタイプ: ファネルチャート。
5. 新規 vs リピーター
- 必要なデータ: 仮名
person_id。最初の分析には2つ以上のウェビナーが必要。 - 計算: 時系列の各ウェビナーについて、その人の最初の出席を「新規」としてマークし、それ以降を「リピーター」としてマーク。期間全体にわたって累積ユニークユーザーも計算。
- チャートタイプ: 積み上げ棒グラフまたはエリアグラフ。
6. 月次成長
- 必要なデータ:
webinar.start_time、attendee_session.attended - 計算:
start_timeを月単位にバケット化。各月のユニーク出席者数をカウント。前月比変化率。 - チャートタイプ: 棒グラフ + 変化率ライン。
7. 定着コホート
- 必要なデータ: 一貫した
person_idを持つ2つ以上のウェビナー。 - 計算: 各コホート(最初のウェビナー月)について、その後の各期間におけるリピート率を計算。
- チャートタイプ: ヒートマップ(コホート x 期間)。
8. 時間帯別
- 必要なデータ:
webinar.start_time(ローカル時間として扱うか、ユーザー指定のタイムゾーンに変換)。 - 計算: 開始時間を1時間のスロットにビン分割(
9:00、10:00など)。各スロットの平均出席者数。 - チャートタイプ: 棒グラフ。
9. テーマクラスタリング(フィードバック)
- 必要なデータ:
feedback_response.liked_textおよび/またはimprove_text。 - 計算(シンプル): 単語頻度(ストップワード除去後)。上位の単語/バイグラムをタグクラウドまたは棒グラフとして表示。
- 計算(高度): テキストを正規化(小文字化、語幹処理)、キーフレーズを抽出、類似フィードバックをクラスタリング。
- チャートタイプ: タグクラウドまたはクラスタリングされたフィードバックリスト。
10. 満足度分布
- 必要なデータ:
feedback_response.score - 計算: スコア(1〜5)ごとのカウント。平均スコア。NPS風の分類(推奨者9〜10、中立7〜8、批判者1〜6 — ただし5段階評価の場合はスケーリング)。
- チャートタイプ: ドーナツまたは水平棒グラフ。
月オーバーライド
ウェビナーを異なるタイムゾーンの視聴者に対して現地の深夜直後に実行する場合、start_time を特定のビジネス月に割り当てる必要がある場合があります。
- ユーザーが各ウェビナーに手動で月を割り当てるためのインターフェース(ドロップダウンまたは日付ピッカー)を提供します。
- このオーバーライドは、月次成長チャートと定着コホートのバケット化にのみ影響します。タイムライン、時間帯別、その他のチャートは
start_timeの実際の値を使用します。 - すべてのウェビナーが常にオーバーライドを必要とするわけではありません。オーバーライドがない場合、
start_timeから月を導出します。
実装ガイドライン
ファイル処理
pandasDataFrameとして読み込む前にファイルを検証します。- ヘッダー行、数値行、空行、UTF-8エンコーディングを処理します。
- タイムスタンプ解析のために、ユーザーに日付形式を指定するよう促します(一般的な形式を推測してみて、間違っている場合は修正を許可します)。
スキーマバージョン管理
- すべてのインポートにバージョンタグを付けます。
- ダッシュボードが新しいスキーマバージョンに更新された場合、新しいデータと既存のデータを同じように扱います。
エラー処理
- マッピングの競合を優雅に処理します(例:2つのカラムが同じ正規フィールドにマップされる)。
- 欠落データに関する説明的なエラーメッセージを表示します。
チャート可用性マトリックス
このマトリックスは、どのデータがどのチャートをロック解除するかを決定します。
| チャート | 必須データ | フォールバック |
|---|---|---|
| 視聴時間分布 | minutes、attended=true | 利用不可の場合、チャートを非表示 |
| 同時視聴者タイムライン | join_time + leave_time、または minutes + 開始時間 | 推定(ユーザーにフラグ) |
| 離脱検出 | minutes または leave_time | 利用不可の場合、チャートを非表示 |
| 出席ファネル | attended、num_registrants または is_registrant | 登録データがない場合、出席者のみ表示 |
| 新規 vs リピーター | 一貫した person_id、2つ以上のウェビナー | 1つだけの場合、チャートを非表示 |
| 月次成長 | start_time、attended、少なくとも2ヶ月 | 利用不可の場合、チャートを非表示 |
| 定着コホート | 一貫した person_id、2つ以上のウェビナー | 利用不可の場合、チャートを非表示 |
| 時間帯別 | start_time | 利用不可の場合、チャートを非表示 |
| テーマクラスタリング | liked_text または improve_text | 利用不可の場合、そのタブを非表示 |
| 満足度分布 | score | 利用不可の場合、チャートを非表示 |
ストレージモデル
すべてのデータは、正規スキーマを反映したリレーショナルデータベースに保存する必要があります。推奨テーブル:
webinars— ウェビナーごとに1行。attendee_sessions— 出席者イベントごとに1行。feedback_responses— アンケート回答ごとに1行。replay_stats— ウェビナーごとに1行。
すべてのAPIクエリはこれらのテーブルに対して実行されます。生のエクスポートファイルは保存されません。
参照
references/platform-exports.md— プラットフォームごとの典型的なカラム名。references/anonymisation.md— 匿名化スクリプトとガイダンス。references/chart-semantics.md— 上記のチャートの詳細な実装。
ライセンス
MIT