Consent gate: 同意するまで何も実行されない
このルールを一言で言うと、「ユーザーがCookieバナーで「同意」をクリックするまで、トラッキングピクセル、分析、サードパーティスクリプトは一切読み込まれない」ことです。ピクセルがすでに発火した後に表示されるバナーは何も修正しません。このスキルはその「待機」部分を構築します。
法的アドバイスではありません。コード、コピー、レポートに「完全準拠」と書かないでください。アプリが今何をするのか、何がテストされたのかを記述してください。
何かに触れる前に
- 監査を実施する。 このアプリに
consent-auditレポートがない場合は、先にそれを実行してください。インベントリが必要です:どのベンダー、どこから始まるか、何を送信するか。 - トラッカーごとに1つの質問を所有者に尋ねる:保持、ゲート、または削除? トラッカーが意思決定や広告に使用されていない場合、ゲートするより削除する方が優れています。必要なストレージのみを使用するサイトにはバナーは一切不要です。追加しないでください。
- 公開によって何がリリースされるかを把握する。 ホステッドビルダー(Lovableなど)は、未公開の変更をすべて一緒に出荷します。それらをリストアップし、公開前に許可を得てください。
- ファーストパーティデータを保護する。 ゲートするトラッカーは、ログイン、支払い、またはアプリ独自のデータベース書き込み(学生の作業、進捗、フォーム)に触れてはいけません。レポートに明記してください。
「ゲート済み」の意味(修正が満たすべきチェックリスト)
読み込み
- 1つの中央ローダー(
src/lib/consent.ts、references/consent.tsを参照)。index.html、ルートレイアウト、またはmain.tsxにピクセル、GTM、gtag、PostHog、リプレイの<script>はなし。 - オプショナルスクリプトはフェッチされない。初期化されないだけでなく、動的
import()またはスクリプトインジェクションはオプトイン後にのみ発生する。 - キューに入ったイベントはリプレイされない:同意前のページビューは破棄され、遅れて送信されることはない。
- サーバーサイド転送(Meta Conversions API、
/api/track、エッジ関数)は、リクエストとともに送信される同じ保存済み選択をチェックする。 - ホストインジェクトされた分析はソースでオフにされる(Lovable → 設定 → ビジター分析オフ;Vercel/Netlify/Cloudflare 分析オフ)、またはインジェクション前にゲートされる。読み込み後にスクリプトを削除しても遅すぎる。最初のリクエストはすでに出ているからだ。
- Google Consent Mode(GA/広告が残る場合):
gtag('consent','default',{ad_storage:'denied',analytics_storage:'denied',ad_user_data:'denied',ad_personalization:'denied'})かつ gtag スクリプト自体も、このスキルのデフォルト設定ではオプトインを待つ。Consent Mode は「ベーシック」を使用し、「アドバンスト」は使用しない。アドバンストは同意前にクッキーレスピングを送信するため。
バナー
- 同意(オプショナル) と 拒否(オプショナル) は同等に目立つ:同じサイズ、同じスタイル、同じクリック数。さらに設定オプションもある。
- カテゴリトグル(分析、広告など)はチェックされていない状態で開始する。
- バナーを閉じる(X / Escape)ことは、拒否を意味する。
- 選択はバージョンと有効期限(6〜12ヶ月)付きで保存される。ベンダーリストを変更するとバージョンが上がり、再度尋ねる。
- フッターに永続的な**「プライバシー設定」**リンクがあり、設定を再度開く。
- 同意を撤回すると、将来の呼び出しが停止し、アプリが所有するオプショナルCookieとストレージ(
_ga*、_fbp、_gcl_au、_ttp、ph_*、ajs_*、_hj*、_clck)が認証に触れずに削除される。 - Global Privacy Control(
navigator.globalPrivacyControl === true)は、広告/販売/共有に対して拒否として扱われ、バナーはそれが尊重されたことを示す。
同意後でも送信されるもの
- ピクセルや分析のペイロードにメール、電話番号、氏名、生年月日データは含まれない(Meta高度なマッチングなし、
identify(email)なし)。本当に必要な場合のみ、不透明なIDを使用する。 - URLは
?queryと#fragmentなしで送信される(ギフトコード、リセットトークン、検索語句)。ベンダーがそれらを削除できない場合、そのベンダーは削除する。 - クイズの回答、チャット内容、健康/金融/生年月日データ、フォームフィールドからの情報は何も送信されない。
- ビデオページ: レッスンやコースの動画を再生するページには広告ピクセルを設置しない(連邦ビデオプライバシー保護法のリスク)。弁護士が別途指示しない限り。
通知
- フッターとサインアップ/ログインページからリンクされた、公開ルート上のプライバシー/Cookie通知。実際のベンダーとカテゴリをリストアップする。実際の運営者名と連絡先メールのみを使用する。アドレス、DPO、法的主張をでっち上げない。
実装方法
- ローカルコード / Claude Code:
references/consent.tsをアプリにコピーし、各オプショナルベンダーをloaderとして登録し、ハードコードされたタグを削除し、アプリ独自のコンポーネントでバナーを構築し、フッターリンクを配線する。差分を小さく保ち、アプリのスタイルに合わせる。 - Lovable / Bolt / v0 / Replit(エージェントビルド):
~/.claude/skills/consent-audit/references/prompts.mdから修正プロンプト(または削除プロンプト)を貼り付ける。その後、自分で確認すること。エージェントの要約を信頼しない。
証明する(完了と言う前に必須)
プレビューでこれらを実行し、公開後にもう一度ライブURLで実行する。Claudeの内蔵ブラウザで、ストレージをクリアした新しいタブを使用し、次に read_network_requests と javascript_tool(document.cookie、localStorage)を使用する:
| テスト | 合格条件 |
|---|---|
| 新規訪問、クリックなし | 広告、分析、リプレイドメインへのリクエスト0件、オプショナルCookieやストレージなし |
| 拒否、その後2回のページ遷移 | まだ0件、バナーは表示されないまま、選択は保存されている |
| 分析のみ同意 | 分析が読み込まれる、広告ピクセルは読み込まれない |
| リロード | 選択が記憶され、バナーは表示されない |
| フッターリンクから撤回 | 将来の呼び出しが停止し、オプショナルCookieがクリアされ、まだログイン状態 |
GPCオン(navigator.globalPrivacyControl を強制的に true) | クリックなしで広告が拒否される |
| クライアントサイドナビゲーション(SPA) | ルート変更時にトラッカーが忍び込まない |
| テストアカウントでサインイン | トラッカーリクエストにメールやユーザーIDが含まれない |
| ビルド + 型チェック | 合格 |
レポート:変更されたファイル、証拠付きの各テスト結果(確認されたドメインまたは「なし」)、実行されなかったテストとその理由、それと一緒に出荷された未公開の変更、および「法的アドバイスではありません。広告を掲載している場合、またはカリフォルニア/EUの訪問者にサービスを提供している場合は、弁護士に確認してください。」