競合店舗調査機能
概要
| 項目 | 内容 |
|---|---|
| ステータス | 🔵 提案中 |
| Issue | - |
| 担当 | - |
検索キーワード × 計測地点で 自店と一緒に表示される競合店舗を一覧化、各競合の順位推移をグラフで提供し、詳細な GBP 情報は Google マップ埋め込みで参照する機能。Places API は IDs Only(無料)枠のみ使用、GBP 詳細データは自社で保持・表示せず Google に直接描画させることで、追加 API 課金 $0 を維持しつつ Google 利用規約を完全遵守する。
| 項目 | 内容 |
|---|---|
| 計測方式 | 既存 Places API (New) Text Search レスポンスから全件 place_id を保存 |
| 表示する自社データ | 順位 / 順位推移 / 新規参入・脱落検出 |
| 表示する競合 GBP 情報 | Google マップ Embed iframe 経由のみ(店名・評価・口コミ・写真・営業時間) |
| 対象 | MAPPY(先行)→ GCOR / PIPIT 順次 |
| API 費用 | $0(IDs Only SKU 維持、Maps Embed API は無制限無料) |
提案内容
背景・課題
- 先方より「競合調査ができる機能が欲しい。検索して GBP の情報やその店舗の順位が見れる」との要望
- 現行のランキング機能は 自店の順位のみ を扱い、検索結果に同時に現れる競合店舗の情報は破棄している
- Places API (New) のレスポンスには上位 60 件の place_id が含まれており、既存実装でも取得済みだが利用されていない
- 既存スクレイピング / Places API 移行で「API 課金は IDs Only($0)を維持」が顧客との合意事項
- Google 利用規約上、競合店舗の名前・評価・口コミ数・営業時間などは 自社 DB へのキャッシュ・自社 UI への直接表示が禁止(place_id のみ無期限保存可、緯度経度は 30 日まで)
- → データ表示部分を Google マップ Embed に丸投げすることで、規約遵守 + 追加課金 0 + 顧客要望充足を同時に成立させる
提案するソリューション
既存 Places API Text Search のレスポンスから 全件 place_id を取得・保存し、画面では place_id を Google マップ Embed iframe に渡すことで、Google 公式 UI 内で店名・評価・口コミ・写真・営業時間・経路を直接描画させる。自社 DB に持つのは順位データのみ。
主な特徴:
- API 課金 $0 維持:FieldMask は引き続き
places.idのみ、追加リクエストなし - 規約完全遵守:保存対象は place_id(無期限可)と順位のみ。店名・評価等は自社で持たない
- 競合の順位推移は自社データで完全に提供可能(自店と同じテーブル設計の流用)
- 新規参入・脱落検出:日次の place_id 集合差分で「先月までいなかった競合の出現」「圏外に消えた競合」を自動検知
- 詳細閲覧は Maps Embed iframe(無制限無料)または
https://www.google.com/maps/place/?q=place_id:XXX形式の外部リンク
機能一覧
| # | 機能名 | 説明 | 優先度 |
|---|---|---|---|
| 1 | 競合 place_id 保存 | Places API レスポンスの全 place_id を順位とともに DB 保存 | 高 |
| 2 | 競合一覧表示 | キーワード×日付指定で上位 N 件を表示、自店ハイライト | 高 |
| 3 | 順位推移グラフ | 自店 + 任意の競合 1〜5 店舗の順位を時系列折線で比較 | 高 |
| 4 | Maps Embed プレビュー | 競合行クリックで Google マップ iframe をモーダル展開 | 高 |
| 5 | Google マップ外部リンク | 「Google マップで見る↗」リンクで別タブ遷移 | 高 |
| 6 | 新規参入検出 | 過去 N 日間に上位に存在しなかった place_id を新着フラグ表示 | 中 |
| 7 | 脱落検出 | 過去 N 日間上位にいたが今日不在の place_id を脱落フラグ表示 | 中 |
| 8 | 競合ヒット数集計 | 1 店舗(place_id)が何キーワードで上位にいるかを集計 | 中 |
| 9 | 順位帯遷移ビュー | 競合の順位帯(1〜3 / 4〜10 / 11〜20 / 圏外)の月次遷移 | 低 |
| 10 | CSV エクスポート(順位のみ) | place_id + 順位のみ CSV 出力(店名・評価等は含めない) | 低 |
設計検討事項
できること・できないこと(重要な前提)
| 情報 | 自社 DB 保存 | 自社画面表示(数値・テキスト) | Maps Embed 内表示 |
|---|---|---|---|
| place_id | ✅ 無期限 | ✅ 内部キー | — |
| 順位(自店・競合) | ✅ | ✅ 数値・グラフ可 | — |
| 競合の店名 | ❌ 規約違反 | ❌ | ✅ Google が描画 |
| 競合の住所 | ❌ | ❌ | ✅ |
| 競合の評価(★) | ❌ | ❌ | ✅ |
| 競合の口コミ数 | ❌ | ❌ | ✅ |
| 競合の営業時間 | ❌ | ❌ | ✅ |
| 競合の写真 | ❌ | ❌ | ✅ |
| 競合のインサイト(PV/通話数等) | ❌ | ❌ | ❌(GBP オーナーのみ) |
規約上できないこと
- 競合店の 店名・評価・口コミ数を自社画面の表に並べて表示
- 競合店の 評価・口コミ数の推移グラフ
- 競合店の 写真を自社サーバーにダウンロード保存
- 競合データの 店名・評価入り CSV エクスポート
これらは Google Maps Platform Terms of Service の「place_id 以外の Places コンテンツを保存・キャッシュしてはならない」条項に抵触する。実装すると API アクセス権剥奪のリスクあり。
採用する設計判断の背景
| 検討案 | 月額追加コスト | 評価 | 採否 |
|---|---|---|---|
| 本案(IDs Only + Maps Embed) | $0 | 規約遵守、コスト0、顧客要望の中核を満たす | 採用 |
| Pro tier 利用(店名・住所表示) | $30〜$100/月 | キャッシュ不可制約で結局毎回フェッチ必要、UX改善ほぼなし | 不採用 |
| Enterprise tier(評価・口コミ数表示) | $100〜$500/月 | 規約上 DB 保存不可で推移グラフ作れず、コスト見合わず | 不採用 |
| Google Business Profile API | — | 規約上競合データ取得は明示禁止(lead generation / competitive analysis) | 不採用 |
| Google 検索スクレイピング | (見えないコスト大) | 規約違反、reCAPTCHA、不安定 | 不採用 |
DB スキーマ拡張案
既存 mappy_place_search_rankings をベースに、自店以外の競合行も保存する形に拡張:
-- 競合スナップショット(自店以外の上位 N 件の place_id を保存)
CREATE TABLE mappy_competitor_snapshots (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
gbp_location_id BIGINT NOT NULL, -- 自店の location(観測の主体)
keyword_id BIGINT NOT NULL,
competitor_place_id VARCHAR(255) NOT NULL, -- 競合の place_id(無期限保存可)
ranking SMALLINT NOT NULL, -- 1〜60 / 0=圏外(理論上競合行は1〜60のみ)
ranking_at DATE NOT NULL,
search_at DATETIME NOT NULL,
source VARCHAR(20) DEFAULT 'places_api',
system_id INT NOT NULL,
created_at DATETIME,
INDEX idx_loc_kw_date (gbp_location_id, keyword_id, ranking_at),
INDEX idx_place (competitor_place_id, ranking_at)
);- 自店行は既存
mappy_place_search_rankingsをそのまま使用(重複保存しない) - 競合行を別テーブルにする理由:行数が約 N 倍(最大 60 倍)に膨らむためインデックス分離
- 保持期間:13 ヶ月(前年同月比較を可能にする最小スパン)
- 約 200 B/rec × N キーワード × 30〜60 件/日 × 13 ヶ月 → 顧客 100 社規模で 約 5〜10 GB
Maps Embed API の利用形態
<!-- 競合詳細モーダル内 -->
<iframe
src="https://www.google.com/maps/embed/v1/place?key={EMBED_KEY}&q=place_id:ChIJ..."
width="100%" height="450" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
allowfullscreen>
</iframe>| 項目 | 仕様 |
|---|---|
| API 種別 | Maps Embed API(Places API とは別 SKU) |
| 料金 | 完全無料・無制限 |
| 必要なキー | Maps Embed 用キー(既存 Places API キーとは別。1 個発行で全社共用可) |
| 取り扱い | キーはフロントエンド埋め込み可(HTTP リファラ制限を設定) |
| 表示内容 | 店名・カテゴリ・評価・口コミ件数・写真・営業時間・経路ボタン |
コスト構造(月額試算)
| 項目 | 試算 |
|---|---|
| Places API 追加呼び出し | 0(既存呼び出しのレスポンスから place_id を抜き出すだけ) |
| Places API 料金増分 | $0 |
| Maps Embed API 利用 | 完全無制限無料 |
| AWS RDS 増分ストレージ(13 ヶ月保持) | 約 +$0.5〜$1.0/月 |
| AWS データ転送 | 微少 |
| 月額追加コスト合計 | 約 ¥100〜200/月(実質ゼロ) |
先方説明用ポイント
- API 課金は完全 $0 維持(既存の IDs Only 方針継続)
- 「競合店舗の詳細情報は Google マップで直接見れる」という形で顧客要望を満たす
- 順位推移・新規参入検出 など 自社プラットフォーム独自の価値を提供
- 顧客への課金転嫁が不要(既存プランの付加価値として提供可)
- 規約遵守設計のため、MEO 業界他社が突破しづらいリーガル面の優位を確保
既存案件・既存実装との関係
- 現行 Places API ランキング取得 の レスポンス側の利用拡張。リクエスト追加なし
- 既存案件 #11 複数箇所計測(ジオグリッドランキング) と組み合わせると 計測点ごとの競合一覧 も生成可能(拡張余地)
- 既存 #7 グループごとの分析・ランキング比較 はグループ内自店間の比較、本案件はグループ外の競合との比較。機能補完関係
画面モック
競合店舗調査
| 順位 | 店舗 | 前月比 | 推移 | 詳細 |
|---|---|---|---|---|
| 1 | place_id: ChIJAbcDefGh… | — | ━━━━━ | |
| 2 | place_id: ChIJXyzPqrSt… | +1 | ╲━━━╱ | |
| 3 | ★ サンプル美容室 渋谷店(自店) | -2 | ╲╲━━━ | — |
| 4 | place_id: ChIJNew00011…NEW | NEW | ----╱ | |
| 5 | place_id: ChIJEfgHijKl… | — | ━━━━━ | |
| 6 | place_id: ChIJDrop0001…↓圏外へ | +4 | ╲╲╲╲━ | |
| 7 | place_id: ChIJNopQrsTu… | -1 | ╱━━━━ | |
| 8 | place_id: ChIJWxyZab00… | +2 | ━━╲━━ | |
| 9 | place_id: ChIJCdeFghIj… | — | ━━━━━ | |
| 10 | place_id: ChIJLmnOpqRs… | +1 | ━╲━━━ |
クリックすると Google マップ Embed が開き、店名・評価・口コミ・写真・営業時間などが Google から直接表示されます。
設計上の表示制限
本モックの「店舗A」「店舗B」等はプレースホルダ表示であり、本番では place_id のみが表示される。実際の店名・評価・口コミ数は モーダル内の Google マップ Embed iframe に Google が直接描画する形となる(自社 UI 内には店名等は出ない)。
画面構成
| 領域 | 内容 |
|---|---|
| ヘッダー | キーワード選択 / 日付選択 / 「順位推移」「競合一覧」タブ切替 |
| 競合一覧テーブル | 順位 / place_id(マスク表示)/ Google マップで見るボタン / 推移ミニグラフ / 新規・脱落フラグ |
| 自店行のハイライト | 自店の順位行のみ店名表示 + 強調色 |
| 順位推移グラフ | 自店 + 選択した競合(最大5件)の順位を時系列折線で比較 |
| Maps Embed モーダル | 競合行クリック時に開く。Google マップ iframe 内で店名・評価・写真等を Google が描画 |
| 新規・脱落バッジ | 「NEW」「圏外へ↓」などのラベル表示 |
| エクスポート | 順位 + place_id のみ CSV ダウンロード(店名等は含めない) |
概算工数(AI前提)
体制
| 役割 | 人数 | 担当内容 |
|---|---|---|
| 設計者 | 1名 | 要件確認 → AIに設計書作成指示 → レビュー → 製造へ指示 |
| 製造者 | 1名 | ISSUEを元にAIに作成指示 → コードレビュー → テスト実施 → デプロイ |
工数内訳
| # | 作業項目 | AIリテイク | レビュー | 工数(人日) | 担当 |
|---|---|---|---|---|---|
| 1 | 要件確認・設計書作成(規約遵守設計含む) | 2回 | 0.5日/回 | 1.0 | 設計者 |
| 2 | DB スキーマ設計・マイグレーション | 1回 | 0.5日/回 | 0.5 | 設計者 |
| 3 | DB マイグレーション実装 | 1回 | 0.5日/回 | 0.5 | 製造者 |
| 4 | places_api 側:全 place_id 保存ロジック追加 | 1回 | 0.5日/回 | 0.5 | 製造者 |
| 5 | mappy 側:CompetitorService 実装(一覧取得 API) | 2回 | 0.5日/回 | 1.0 | 製造者 |
| 6 | mappy 側:順位推移取得 API | 1回 | 0.5日/回 | 0.5 | 製造者 |
| 7 | mappy 側:新規参入・脱落検出ロジック | 2回 | 0.5日/回 | 1.0 | 製造者 |
| 8 | フロント:競合一覧画面 + Maps Embed モーダル | 2回 | 0.5日/回 | 1.5 | 製造者 |
| 9 | フロント:順位推移グラフ(chart.js / 既存流用) | 1回 | 0.5日/回 | 1.0 | 製造者 |
| 10 | Maps Embed 用キー発行・リファラ制限設定 | 1回 | 0.5日/回 | 0.5 | 製造者 |
| 11 | CSV エクスポート(place_id + 順位のみ) | 1回 | 0.5日/回 | 0.5 | 製造者 |
| 12 | 結合テスト・規約遵守チェックリスト確認 | 1回 | 0.5日/回 | 1.0 | 製造者 |
| 13 | デプロイ・動作確認 | 1回 | 0.5日/回 | 0.5 | 製造者 |
合計:9.5 人日
前提条件・制約
- API 費用は Places API IDs Only ($0) 維持。Field Mask 拡張は本案件範囲外
- 競合店の店名・評価・口コミ数等を自社 UI に直接表示する要望が出た場合は、Google Maps Platform Terms of Service の制約説明 + Pro/Enterprise tier 課金検討の別案件化 を推奨
- Maps Embed iframe の表示内容(店名・評価等)は Google の仕様変更に依存。Google 側 UI 変更時は表示内容が変わる可能性あり(自社管理外)
- 保存対象は place_id + 順位のみ。緯度経度は 30 日上限の規約があるため保存しない
- 既存 Places API リクエストのレスポンスを利用する設計のため、本機能のためだけの追加 API 呼び出しは発生しない
先方確認事項
- 保存する競合数の上限:上位 10 件 / 20 件 / 全 60 件 — どこまで保持するか
- 保持期間:13 ヶ月(前年同月比較)/ 24 ヶ月(2 年推移)/ 6 ヶ月(軽量運用)
- 計測頻度:既存自店計測と同じ日次でよいか
- 競合詳細の表示方式:Maps Embed iframe を画面内モーダルで表示 / Google マップへの外部リンクのみ / 両対応
- アクセス権:全アカウント開放 / 上位プランのみのオプション機能 / 試験運用として一部顧客から開始
- 「店名を表で並べたい」要望対応:Pro tier 課金(月 $30〜$100)に進む可能性を許容するか、無料案で完結させるか
スケジュール
| タスク | 担当 | 日数 | 6/15 | 6/16 | 6/17 | 6/18 | 6/19 | 6/20 | 6/21 | 6/22 | 6/23 | 6/24 | 6/25 | 6/26 | 6/27 | 6/28 | 6/29 | 6/30 | 7/1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | 木 | 金 | 土 | 日 | 月 | 火 | 水 | |||
| 要件確認・設計書 | 設計 | 1d | |||||||||||||||||
| DBスキーマ設計 | 設計 | 1d | |||||||||||||||||
| DBマイグレーション | 実装 | 1d | |||||||||||||||||
| place_id保存ロジック | 実装 | 1d | |||||||||||||||||
| CompetitorService | 実装 | 1d | |||||||||||||||||
| 推移取得API | 実装 | 1d | |||||||||||||||||
| 新規・脱落検出 | 実装 | 1d | |||||||||||||||||
| 一覧画面+Maps Embed | 実装 | 2d | |||||||||||||||||
| 推移グラフ | 実装 | 1d | |||||||||||||||||
| Embedキー・CSV | 実装 | 1d | |||||||||||||||||
| 結合テスト | テスト | 1d | |||||||||||||||||
| デプロイ | デプロイ | 1d |