cookie-consent
EU一般データ保護規則(GDPR)やePrivacy指令に準拠したCookie同意管理を実装し、Cookieバナーの表示、マーケティング同意の管理、分析プラットフォームとの連携などをスムーズに行えるようにするSkill。
📜 元の英語説明(参考)
Implement GDPR/ePrivacy-compliant cookie consent management. Use when adding a cookie banner, managing marketing consent, achieving GDPR compliance for EU users, or integrating consent management with analytics platforms.
🇯🇵 日本人クリエイター向け解説
EU一般データ保護規則(GDPR)やePrivacy指令に準拠したCookie同意管理を実装し、Cookieバナーの表示、マーケティング同意の管理、分析プラットフォームとの連携などをスムーズに行えるようにするSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o cookie-consent.zip https://jpskill.com/download/14788.zip && unzip -o cookie-consent.zip && rm cookie-consent.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/14788.zip -OutFile "$d\cookie-consent.zip"; Expand-Archive "$d\cookie-consent.zip" -DestinationPath $d -Force; ri "$d\cookie-consent.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
cookie-consent.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
cookie-consentフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Cookie Consent
概要
EUのePrivacy指令(Cookie法)およびGDPRでは、必須ではないCookieを配置する前に、情報に基づいた、自由に与えられた、粒度の細かい、撤回可能な同意が必要です。英国のPECRは、Brexit後に適用されます。GDPRに基づく罰金は、世界の年間売上高の4%に達する可能性があります。
厳密に必要なCookie(同意は不要):セッショントークン、ショッピングカート、セキュリティトークン、ロードバランシング。
その他すべては同意が必要: アナリティクス、広告、パーソナライゼーション、機能拡張。
Cookieのカテゴリ
| カテゴリ | 例 | 同意が必要か |
|---|---|---|
| 厳密に必要なもの | 認証セッション、CSRFトークン、カート | ❌ いいえ |
| 機能 | 言語設定、UIテーマ | ✅ はい (GDPR) |
| アナリティクス | Google Analytics, Mixpanel, Hotjar | ✅ はい |
| マーケティング | Facebook Pixel, Google Ads, 広告ターゲティング | ✅ はい |
同意要件 (GDPR 第7条)
- 粒度: カテゴリごとの同意 (オール・オア・ナッシングではない)
- 自由に与えられた: 「すべてを受け入れる」≠ より良い扱い。拒否は受け入れと同じくらい簡単でなければならない
- 情報に基づいた: 各カテゴリが何をするかの明確な説明
- 撤回可能: ユーザーはいつでも同意を変更または取り消すことができる
- 文書化: 同意記録を保存する (誰が、いつ、何に、どのバージョンで同意したか)
カスタム同意バナー (React/Next.js)
// components/CookieConsent.tsx
import { useState, useEffect } from 'react';
interface ConsentPreferences {
strictly_necessary: true; // 常にtrue — 無効にすることはできません
functional: boolean;
analytics: boolean;
marketing: boolean;
}
interface ConsentRecord {
version: string;
timestamp: string;
preferences: ConsentPreferences;
source: 'banner' | 'settings' | 'gpc';
}
const CONSENT_VERSION = '2024-01-01';
const CONSENT_COOKIE_NAME = 'consent_preferences';
export function CookieConsent() {
const [showBanner, setShowBanner] = useState(false);
const [showDetails, setShowDetails] = useState(false);
const [preferences, setPreferences] = useState<ConsentPreferences>({
strictly_necessary: true,
functional: false,
analytics: false,
marketing: false,
});
useEffect(() => {
// 最初にGPCシグナルを確認する
if (navigator.globalPrivacyControl) {
const gpcConsent: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: { strictly_necessary: true, functional: false, analytics: false, marketing: false },
source: 'gpc',
};
saveConsent(gpcConsent);
return;
}
// 同意がすでに与えられているか確認する
const saved = getStoredConsent();
if (!saved || saved.version !== CONSENT_VERSION) {
setShowBanner(true);
}
}, []);
const acceptAll = () => {
const allConsent: ConsentPreferences = {
strictly_necessary: true,
functional: true,
analytics: true,
marketing: true,
};
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: allConsent,
source: 'banner',
};
saveConsent(record);
applyConsent(allConsent);
setShowBanner(false);
};
const rejectAll = () => {
const minimalConsent: ConsentPreferences = {
strictly_necessary: true,
functional: false,
analytics: false,
marketing: false,
};
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: minimalConsent,
source: 'banner',
};
saveConsent(record);
applyConsent(minimalConsent);
setShowBanner(false);
};
const saveCustom = () => {
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: preferences,
source: 'banner',
};
saveConsent(record);
applyConsent(preferences);
setShowBanner(false);
};
if (!showBanner) return null;
return (
<div className="fixed bottom-0 left-0 right-0 z-50 bg-white border-t shadow-lg p-6">
<div className="max-w-4xl mx-auto">
<h2 className="text-lg font-semibold mb-2">Cookie Preferences</h2>
<p className="text-sm text-gray-600 mb-4">
We use cookies to improve your experience. You can choose which categories to allow.
<a href="/privacy-policy" className="underline ml-1">Learn more</a>
</p>
{showDetails && (
<div className="mb-4 space-y-3">
{[
{ key: 'strictly_necessary', label: 'Strictly Necessary', desc: 'Required for the site to function. Cannot be disabled.', locked: true },
{ key: 'functional', label: 'Functional', desc: 'Remember your preferences (language, theme).' },
{ key: 'analytics', label: 'Analytics', desc: 'Help us understand how you use our site (Google Analytics, Mixpanel).' },
{ key: 'marketing', label: 'Marketing', desc: 'Show relevant ads and measure campaign effectiveness.' },
].map(({ key, label, desc, locked }) => (
<div key={key} className="flex items-start gap-3">
<input
type="checkbox"
id={key}
checked={preferences[key as keyof ConsentPreferences] as boolean}
disabled={locked}
onChange={(e) => setPreferences(prev => ({ ...prev, [key]: e.target.checked }))}
className="mt-1"
/>
<label htmlFor={key} className="text-sm">
<strong>{label}</strong> {locked && <span className="text-gray-400">(Always on)</span>}
<p className="text-gray-500">{desc}</p>
</label>
</div>
))}
</div>
)}
<div className="flex flex-wrap gap-2">
<button onClick={rejectAll} className="px-4 py-2 border rounded text-sm">Reject All</button>
<button onClick={() => setShowDetails(!showDetails)} className= 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Cookie Consent
Overview
The EU ePrivacy Directive (Cookie Law) and GDPR require informed, freely given, granular, and withdrawable consent before placing non-essential cookies. The UK PECR applies post-Brexit. Fines under GDPR can reach 4% of global annual turnover.
Strictly necessary cookies (no consent required): session tokens, shopping cart, security tokens, load balancing.
All others require consent: analytics, advertising, personalization, functional enhancements.
Cookie Categories
| Category | Examples | Consent Required |
|---|---|---|
| Strictly Necessary | Auth session, CSRF token, cart | ❌ No |
| Functional | Language preference, UI theme | ✅ Yes (GDPR) |
| Analytics | Google Analytics, Mixpanel, Hotjar | ✅ Yes |
| Marketing | Facebook Pixel, Google Ads, ad targeting | ✅ Yes |
Consent Requirements (GDPR Article 7)
- Granular: Per-category consent (not all-or-nothing)
- Freely given: "Accept all" ≠ better treatment; reject must be as easy as accept
- Informed: Clear explanation of what each category does
- Withdrawable: Users can change or revoke consent at any time
- Documented: Store a consent record (who consented, when, to what, via which version)
Custom Consent Banner (React/Next.js)
// components/CookieConsent.tsx
import { useState, useEffect } from 'react';
interface ConsentPreferences {
strictly_necessary: true; // Always true — cannot be disabled
functional: boolean;
analytics: boolean;
marketing: boolean;
}
interface ConsentRecord {
version: string;
timestamp: string;
preferences: ConsentPreferences;
source: 'banner' | 'settings' | 'gpc';
}
const CONSENT_VERSION = '2024-01-01';
const CONSENT_COOKIE_NAME = 'consent_preferences';
export function CookieConsent() {
const [showBanner, setShowBanner] = useState(false);
const [showDetails, setShowDetails] = useState(false);
const [preferences, setPreferences] = useState<ConsentPreferences>({
strictly_necessary: true,
functional: false,
analytics: false,
marketing: false,
});
useEffect(() => {
// Check for GPC signal first
if (navigator.globalPrivacyControl) {
const gpcConsent: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: { strictly_necessary: true, functional: false, analytics: false, marketing: false },
source: 'gpc',
};
saveConsent(gpcConsent);
return;
}
// Check if consent already given
const saved = getStoredConsent();
if (!saved || saved.version !== CONSENT_VERSION) {
setShowBanner(true);
}
}, []);
const acceptAll = () => {
const allConsent: ConsentPreferences = {
strictly_necessary: true,
functional: true,
analytics: true,
marketing: true,
};
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: allConsent,
source: 'banner',
};
saveConsent(record);
applyConsent(allConsent);
setShowBanner(false);
};
const rejectAll = () => {
const minimalConsent: ConsentPreferences = {
strictly_necessary: true,
functional: false,
analytics: false,
marketing: false,
};
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: minimalConsent,
source: 'banner',
};
saveConsent(record);
applyConsent(minimalConsent);
setShowBanner(false);
};
const saveCustom = () => {
const record: ConsentRecord = {
version: CONSENT_VERSION,
timestamp: new Date().toISOString(),
preferences: preferences,
source: 'banner',
};
saveConsent(record);
applyConsent(preferences);
setShowBanner(false);
};
if (!showBanner) return null;
return (
<div className="fixed bottom-0 left-0 right-0 z-50 bg-white border-t shadow-lg p-6">
<div className="max-w-4xl mx-auto">
<h2 className="text-lg font-semibold mb-2">Cookie Preferences</h2>
<p className="text-sm text-gray-600 mb-4">
We use cookies to improve your experience. You can choose which categories to allow.
<a href="/privacy-policy" className="underline ml-1">Learn more</a>
</p>
{showDetails && (
<div className="mb-4 space-y-3">
{[
{ key: 'strictly_necessary', label: 'Strictly Necessary', desc: 'Required for the site to function. Cannot be disabled.', locked: true },
{ key: 'functional', label: 'Functional', desc: 'Remember your preferences (language, theme).' },
{ key: 'analytics', label: 'Analytics', desc: 'Help us understand how you use our site (Google Analytics, Mixpanel).' },
{ key: 'marketing', label: 'Marketing', desc: 'Show relevant ads and measure campaign effectiveness.' },
].map(({ key, label, desc, locked }) => (
<div key={key} className="flex items-start gap-3">
<input
type="checkbox"
id={key}
checked={preferences[key as keyof ConsentPreferences] as boolean}
disabled={locked}
onChange={(e) => setPreferences(prev => ({ ...prev, [key]: e.target.checked }))}
className="mt-1"
/>
<label htmlFor={key} className="text-sm">
<strong>{label}</strong> {locked && <span className="text-gray-400">(Always on)</span>}
<p className="text-gray-500">{desc}</p>
</label>
</div>
))}
</div>
)}
<div className="flex flex-wrap gap-2">
<button onClick={rejectAll} className="px-4 py-2 border rounded text-sm">Reject All</button>
<button onClick={() => setShowDetails(!showDetails)} className="px-4 py-2 border rounded text-sm">
{showDetails ? 'Hide Details' : 'Customize'}
</button>
{showDetails && (
<button onClick={saveCustom} className="px-4 py-2 bg-blue-600 text-white rounded text-sm">Save Preferences</button>
)}
<button onClick={acceptAll} className="px-4 py-2 bg-blue-600 text-white rounded text-sm">Accept All</button>
</div>
</div>
</div>
);
}
Consent Storage and Retrieval
// lib/consent.ts
const CONSENT_KEY = 'consent_v2';
export function saveConsent(record: ConsentRecord): void {
// Store in localStorage for JS access
localStorage.setItem(CONSENT_KEY, JSON.stringify(record));
// Also set a cookie for server-side access
const expires = new Date();
expires.setFullYear(expires.getFullYear() + 1);
document.cookie = `${CONSENT_KEY}=${encodeURIComponent(JSON.stringify(record))}; expires=${expires.toUTCString()}; path=/; SameSite=Strict; Secure`;
// Optionally send to your backend for audit trail
fetch('/api/consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(record),
keepalive: true,
}).catch(() => {}); // Best effort
}
export function getStoredConsent(): ConsentRecord | null {
try {
const stored = localStorage.getItem(CONSENT_KEY);
return stored ? JSON.parse(stored) : null;
} catch {
return null;
}
}
export function hasConsent(category: keyof ConsentPreferences): boolean {
const consent = getStoredConsent();
return consent?.preferences[category] === true;
}
Consent-Gated Analytics
// lib/analytics.ts — Only load analytics after consent
export function applyConsent(preferences: ConsentPreferences): void {
if (preferences.analytics) {
loadGoogleAnalytics();
loadMixpanel();
} else {
// Opt out / remove tracking
window['ga-disable-G-XXXXXXXX'] = true;
// Remove existing analytics cookies
deleteCookie('_ga');
deleteCookie('_gid');
deleteCookie('_gat');
}
if (preferences.marketing) {
loadFacebookPixel();
loadGoogleAds();
}
}
function loadGoogleAnalytics(): void {
if (document.getElementById('ga-script')) return; // Already loaded
const script = document.createElement('script');
script.id = 'ga-script';
script.async = true;
script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX';
document.head.appendChild(script);
window.dataLayer = window.dataLayer || [];
function gtag(...args: unknown[]) { window.dataLayer.push(args); }
gtag('js', new Date());
gtag('config', 'G-XXXXXXXX', { anonymize_ip: true });
}
function deleteCookie(name: string): void {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${window.location.hostname}`;
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${window.location.hostname}`;
}
GPC (Global Privacy Control) Detection
// middleware/gpc.js — Next.js middleware to detect GPC
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
// GPC header: Sec-GPC: 1
const gpc = request.headers.get('sec-gpc');
if (gpc === '1') {
// Signal to client that GPC was detected
response.headers.set('X-GPC-Detected', '1');
// Set a cookie to persist for this session
response.cookies.set('gpc_optout', '1', {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 365 // 1 year
});
}
return response;
}
Consent Record API (Backend)
// pages/api/consent.ts — Store consent for audit trail
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') return res.status(405).end();
const { version, timestamp, preferences, source } = req.body;
await db.consentRecords.create({
user_id: req.session?.userId || null, // null for anonymous
session_id: req.session?.id,
ip_address: req.headers['x-forwarded-for'] || req.socket.remoteAddress,
user_agent: req.headers['user-agent'],
consent_version: version,
consented_at: timestamp,
preferences: JSON.stringify(preferences),
source, // 'banner' | 'settings' | 'gpc'
});
res.status(204).end();
}
CMP Platforms (Alternatives to Custom Build)
| Platform | Pricing | IAB TCF | GPC | Notes |
|---|---|---|---|---|
| Cookiebot | From $9/mo | ✅ | ✅ | Auto-scan cookies, DSGVO certified |
| OneTrust | Enterprise | ✅ | ✅ | Full compliance suite |
| Osano | From $49/mo | ✅ | ✅ | SOC 2 certified, privacy-first |
| Usercentrics | From €60/mo | ✅ | ✅ | Popular in EU |
| Termly | Free tier | ❌ | ✅ | Simple, good for small sites |
IAB TCF 2.2 (Transparency and Consent Framework) is required if you work with ad networks. Use a certified CMP.
Compliance Checklist
- [ ] Cookie audit completed (all cookies inventoried by category)
- [ ] No non-essential cookies set before consent
- [ ] "Reject all" option as prominent as "Accept all"
- [ ] Granular per-category consent options available
- [ ] Consent withdrawal option in privacy settings page
- [ ] Consent stored with version, timestamp, and preferences
- [ ] GPC signal detected and honored automatically
- [ ] Privacy policy linked from banner
- [ ] Cookie policy lists all cookies with purpose and retention
- [ ] Third-party scripts blocked until consent granted
- [ ] Analytics opt-out cookies cleared on consent withdrawal
- [ ] Banner tested in EU with VPN (actually applies)
- [ ] Consent renewed when policy version changes