マッチングサービスでは、プロフィールの充実度がユーザー体験を大きく左右します。プロフィールがスカスカだと、相手に自分を知ってもらえない。でも、入力項目が多いと面倒で離脱してしまう。
BandBridge(ミュージシャンマッチングサービス)の開発で、この課題に取り組みました。答えとして Claude Code で実装したのが「プロフィール完成度インジケーター」です。
この記事では、完成度インジケーターの設計思想と実装について解説します。
なぜ完成度インジケーターを作ったのか
2026年1月12日の開発日記にはこう書いています:
プロフィール完成度: ユーザーに「どこまで入力すれば魅力的になるか」を示すことで、入力率を上げる
マッチングサービスでは、プロフィールが「商品」です。プロフィールが充実しているほど、相手の目に留まりやすくなり、マッチング率が上がります。
しかし、ユーザーは「何を入力すればいいか」がわからない。入力フォームを見て「全部埋めるの面倒だな」と思って離脱してしまう。
完成度インジケーターは、この問題を解決します:
- 進捗の可視化: 「あと何を入力すれば良いか」が一目でわかる
- ゲーミフィケーション: 進捗バーを埋めたくなる心理を活用
- 優先順位の提示: 重要な項目から入力を促せる
完成度インジケーターの心理学
開発日記からの学び:
- プロフィール完成度インジケーターは、ゲーミフィケーションの一種。進捗バーがあると埋めたくなる心理
これは「ツァイガルニク効果」と呼ばれる心理現象と関連しています。人は「未完了のタスク」を気にかける傾向があり、完了させたくなる衝動を感じます。
LinkedIn のプロフィール完成度バーが有名ですが、以下のサービスでも同様のパターンが使われています:
- LinkedIn: プロフィール強度(初級→中級→上級)
- Twitter/X: プロフィール設定のチェックリスト
- GitHub: プロフィール README の促進
項目とウェイトの設計
完成度の計算で重要なのは、項目ごとのウェイト(重み)設定です。
2026年1月12日の開発日記から:
完成度の計算: 何をどれくらいの重みで計算するか。必須項目(名前、パート)は重く、任意項目(機材)は軽く
BandBridge のプロフィールでは、以下の項目を設定しました:
| 項目 | ウェイト | 理由 |
|---|---|---|
| 名前 | 15% | 最も基本的な情報、必須 |
| 担当パート | 15% | マッチングの核心、必須 |
| 活動地域 | 10% | 地理的なマッチングに必要 |
| プロフィール画像 | 10% | 視覚的な印象、重要 |
| 自己紹介文 | 10% | 人柄を伝える |
| 活動ステータス | 5% | 「バンド加入希望」など |
| 影響を受けたアーティスト | 10% | 音楽的な趣味の一致 |
| SNS リンク | 5% | 外部での活動を示す |
| 使用機材 | 5% | 詳細情報、機材オタク向け |
| YouTube 動画 | 10% | 演奏を見せられる |
| 音源 | 5% | SoundCloud/Spotify |
合計 100% になるように配分しました。
実装:完成度の計算
interface ProfileField {
key: keyof Profile;
weight: number;
check: (value: any) => boolean;
}
const PROFILE_FIELDS: ProfileField[] = [
{ key: 'name', weight: 15, check: v => !!v },
{ key: 'part', weight: 15, check: v => !!v },
{ key: 'region', weight: 10, check: v => !!v },
{ key: 'avatarUrl', weight: 10, check: v => !!v },
{ key: 'bio', weight: 10, check: v => v && v.length >= 20 },
{ key: 'status', weight: 5, check: v => !!v },
{ key: 'influences', weight: 10, check: v => v && v.length >= 1 },
{ key: 'snsLinks', weight: 5, check: v => v && Object.keys(v).length >= 1 },
{ key: 'equipment', weight: 5, check: v => v && v.length >= 1 },
{ key: 'youtubeVideos', weight: 10, check: v => v && v.length >= 1 },
{ key: 'audioTracks', weight: 5, check: v => v && v.length >= 1 },
];
function calculateCompletion(profile: Profile): number {
let totalWeight = 0;
for (const field of PROFILE_FIELDS) {
if (field.check(profile[field.key])) {
totalWeight += field.weight;
}
}
return totalWeight;
}
最大件数の設計
2026年1月12日の開発日記から:
最大件数の設定: 影響アーティスト10組、機材20個、YouTube動画3つ。多すぎるとUIが崩れる、少なすぎると表現できない
「影響を受けたアーティスト」を無制限にすると、100組も入力するユーザーが出てくるかもしれません。そうなるとプロフィールページのUIが崩れます。
逆に「3組まで」と絞りすぎると、「もっと入れたいのに」という不満が出ます。
最大件数の設計は、UIの限界から逆算しました:
最大件数の設定は、UIの限界から逆算する。スマホで見たときに崩れないかを基準に
| 項目 | 最大件数 | 理由 |
|---|---|---|
| 影響を受けたアーティスト | 10組 | 2列×5行でスマホに収まる |
| 使用機材 | 20個 | 機材オタクは多い、スクロールで対応 |
| YouTube動画 | 3つ | 埋め込みは重い、3つで十分 |
| 音源 | 3つ | 動画と同様 |
バンド完成度の追加
プロフィールに続いて、バンドページにも完成度インジケーターを追加しました。
2026年1月14日の開発日記から:
バンド完成度: プロフィールと同様に、バンドページも「どこまで入力すれば魅力的になるか」を可視化したかった。10項目チェック(バンド名/画像/ジャンル/地域/頻度/紹介文/音源/動画/SNS/結成年)で網羅性を確保
バンドとプロフィールで項目が異なるため、Claude Code で別々の計算ロジックを用意しました:
const BAND_FIELDS: ProfileField[] = [
{ key: 'name', weight: 15, check: v => !!v },
{ key: 'imageUrl', weight: 10, check: v => !!v },
{ key: 'genres', weight: 10, check: v => v && v.length >= 1 },
{ key: 'region', weight: 10, check: v => !!v },
{ key: 'frequency', weight: 5, check: v => !!v },
{ key: 'description', weight: 15, check: v => v && v.length >= 50 },
{ key: 'audioTracks', weight: 10, check: v => v && v.length >= 1 },
{ key: 'youtubeVideos', weight: 10, check: v => v && v.length >= 1 },
{ key: 'snsLinks', weight: 10, check: v => v && Object.keys(v).length >= 1 },
{ key: 'foundedYear', weight: 5, check: v => !!v },
];
ウェイト調整の試行錯誤
2026年1月14日の開発日記から:
- 自己紹介のウェイト調整(15%→10%)で、他の項目とのバランスを取るのに悩んだ
最初は「自己紹介文」を15%に設定していましたが、テストしてみると問題が見つかりました。自己紹介だけ書いて他が空だと、45%まで到達してしまう。「半分くらい埋まったな」と満足してしまい、他の項目を埋めなくなる可能性がありました。
そこで自己紹介を10%に下げ、代わりに「影響を受けたアーティスト」を10%に上げました。音楽的な趣味の一致はマッチングにおいて重要だからです。
UI コンポーネントの実装
interface CompletionIndicatorProps {
completion: number;
missingFields: string[];
}
function CompletionIndicator({
completion,
missingFields
}: CompletionIndicatorProps) {
const getColor = () => {
if (completion >= 80) return 'bg-green-500';
if (completion >= 50) return 'bg-yellow-500';
return 'bg-red-500';
};
return (
<div className="space-y-2">
{/* プログレスバー */}
<div className="flex items-center gap-3">
<div className="flex-1 h-2 bg-gray-200 rounded-full">
<div
className={`h-full rounded-full ${getColor()}`}
style={{ width: `${completion}%` }}
/>
</div>
<span className="text-sm font-medium">{completion}%</span>
</div>
{/* 未入力項目のヒント */}
{missingFields.length > 0 && (
<p className="text-sm text-gray-500">
あと「{missingFields[0]}」を入力すると完成度が上がります
</p>
)}
</div>
);
}
ポイント:
- 色で状態を示す: 80%以上で緑、50%以上で黄、それ以下で赤
- 次のアクションを提示: 「あと〇〇を入力すると」で具体的な行動を促す
- シンプルなUI: 情報過多にならないよう、最低限の表示に
活動ステータスの追加
2026年1月14日の開発日記から:
活動ステータス: 「バンド加入希望」「サポート受付中」などのステータスは、マッチングにおいて重要な情報。完成度に含めることで入力を促進
活動ステータスは後から追加した項目です。マッチングサービスでは、「今バンドを探している」のか「とりあえず登録しただけ」なのかが重要な情報です。
これを完成度に含めることで、自然と入力を促せます。5%という低めのウェイトですが、「あとステータスを設定すると100%」という状況で効果を発揮します。
学んだこと
完成度インジケーターの実装を通じて学んだこと:
1. ウェイトは仮説→検証で調整する
最初から完璧なウェイト配分はできません。実際のユーザー行動を見ながら調整していく必要があります。
2. 「次のアクション」を示す
「完成度60%」だけでなく、「あと〇〇を入力すると」という具体的なアクションを示すと、入力率が上がります。
3. 必須項目と任意項目を区別する
すべての項目を同じウェイトにすると、重要な情報(名前、担当パート)が埋まらないままになる可能性があります。必須項目は高いウェイトに設定すべきです。
4. 100%を目指しやすくする
完成度が95%で止まっていると気持ち悪い。最後の項目は軽めのウェイトにして、「あと一歩で100%」という状況を作りやすくすると効果的です。
効果の考察
完成度インジケーター導入後、以下の変化を期待しています:
- プロフィール入力率の向上: 目標値が可視化されることで、最後まで入力するモチベーションが生まれる
- マッチング率の向上: プロフィールが充実することで、相手に自分を知ってもらいやすくなる
- 離脱率の低下: 「何を入力すればいいかわからない」という離脱が減る
今後、実際の数値で効果を検証していく予定です。
まとめ
プロフィール完成度インジケーターの設計ポイント:
- 項目ごとのウェイト設定: 重要な項目は高く、任意項目は低く
- 最大件数の制限: UIの限界から逆算して決める
- 次のアクションを提示: 具体的な行動を促す
- 色で状態を示す: 進捗状況を直感的に伝える
ゲーミフィケーションの力を借りて、ユーザーに「埋めたい」と思わせる。完成度インジケーターは、シンプルながら効果的なUXパターンです。
Zeronova(ゼロノバ)
Product Manager / AI-Native Builder
Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。