無料ツール

Cookie同意バナー生成ツール

Cookieのカテゴリを選び、文言を書き、見た目を選ぶだけで、どのサイトにも貼り付けられる依存関係なしの同意バナーをコピーできます。訪問者の選択を保存し、タグ付けしたスクリプトはカテゴリが許可されるまでブロックし、フッターのリンクから再表示もできます。

サイトの動作に必要です。常に有効で、同意を求めません。
サイトの利用状況を計測し、改善に役立てます。
広告のパーソナライズとキャンペーンの計測に使用します。
言語・地域・レイアウトなどの選択を記憶します。

あなたの同意バナー

すべてのページで、閉じるbodyタグの直前に貼り付けてください。

<!-- Cookie consent banner - paste this just before </body> -->
<script>
(function () {
  var CFG = {
  "storageKey": "cookie_consent",
  "position": "bar",
  "theme": "light",
  "accent": "#a6144d",
  "title": "Cookieを使用しています",
  "message": "当サイトの運営、利用状況の把握、改善のためにCookieを使用しています。すべて許可する、任意のものを拒否する、カテゴリごとに選ぶ、のいずれも可能です。",
  "policyUrl": "https://example.com/privacy",
  "policyLabel": "プライバシーポリシーを読む",
  "accept": "すべて許可",
  "reject": "任意を拒否",
  "prefs": "設定",
  "save": "選択を保存",
  "categories": [
    {
      "id": "necessary",
      "label": "必須",
      "desc": "サイトの動作に必要です。常に有効で、同意を求めません。",
      "required": true
    },
    {
      "id": "analytics",
      "label": "分析",
      "desc": "サイトの利用状況を計測し、改善に役立てます。",
      "required": false
    },
    {
      "id": "marketing",
      "label": "マーケティング",
      "desc": "広告のパーソナライズとキャンペーンの計測に使用します。",
      "required": false
    }
  ]
};
  var KEY = CFG.storageKey;
  var doc = document;
  var box = null;

  function read() {
    try { return JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) { return null; }
  }

  function save(consent) {
    consent.necessary = true;
    consent.date = new Date().toISOString();
    try { localStorage.setItem(KEY, JSON.stringify(consent)); } catch (e) {}
    unblock(consent);
    window.dispatchEvent(new CustomEvent('consentchange', { detail: consent }));
    if (typeof window.onConsentChange === 'function') window.onConsentChange(consent);
  }

  // Scripts the site parked behind a category run only once it is granted. Park
  // one by giving its tag type="text/plain" and data-consent="analytics".
  // (Deliberately described, not shown: a literal script tag written out here
  // would close this one early and truncate everything below it.)
  function unblock(consent) {
    var parked = doc.querySelectorAll('script[type="text/plain"][data-consent]');
    for (var i = 0; i < parked.length; i++) {
      var old = parked[i];
      if (!consent[old.getAttribute('data-consent')]) continue;
      var next = doc.createElement('script');
      for (var a = 0; a < old.attributes.length; a++) {
        var at = old.attributes[a];
        if (at.name !== 'type' && at.name !== 'data-consent') next.setAttribute(at.name, at.value);
      }
      next.text = old.text;
      old.parentNode.replaceChild(next, old);
    }
  }

  function styles() {
    var dark = CFG.theme === 'dark';
    var bg = dark ? '#161622' : '#ffffff';
    var fg = dark ? '#f4f4f8' : '#141a47';
    var muted = dark ? 'rgba(244,244,248,.72)' : 'rgba(20,26,71,.7)';
    var line = dark ? 'rgba(255,255,255,.14)' : 'rgba(20,26,71,.12)';
    var el = doc.createElement('style');
    el.textContent = [
      '.cc-root{position:fixed;z-index:2147483000;font:400 14px/1.55 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:' + fg + ';box-sizing:border-box}',
      '.cc-root *,.cc-root *::before,.cc-root *::after{box-sizing:inherit}',
      '.cc-card{background:' + bg + ';border:1px solid ' + line + ';box-shadow:0 18px 48px rgba(0,0,0,.18);border-radius:14px;padding:20px}',
      '.cc-bar{left:0;right:0;bottom:0;padding:16px}',
      '.cc-bar .cc-card{display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between;max-width:1120px;margin:0 auto}',
      '.cc-box{left:16px;bottom:16px;max-width:400px}',
      '.cc-modal{inset:0;display:flex;align-items:center;justify-content:center;padding:16px;background:rgba(10,10,20,.5)}',
      '.cc-modal .cc-card{max-width:520px;width:100%}',
      '.cc-title{margin:0 0 6px;font-size:16px;font-weight:700}',
      '.cc-text{margin:0;color:' + muted + '}',
      '.cc-text a{color:' + CFG.accent + ';font-weight:600}',
      '.cc-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}',
      '.cc-bar .cc-actions{margin-top:0}',
      '.cc-btn{appearance:none;cursor:pointer;border:1px solid ' + line + ';border-radius:999px;padding:9px 18px;font:600 14px inherit;background:transparent;color:' + fg + '}',
      '.cc-btn-main{background:' + CFG.accent + ';border-color:' + CFG.accent + ';color:#fff}',
      '.cc-btn:focus-visible{outline:2px solid ' + CFG.accent + ';outline-offset:2px}',
      '.cc-cats{display:none;margin:14px 0 0;padding:14px 0 0;border-top:1px solid ' + line + '}',
      '.cc-cats.cc-open{display:block}',
      '.cc-cat{display:flex;gap:10px;align-items:flex-start;margin-bottom:12px}',
      '.cc-cat input{margin:3px 0 0;accent-color:' + CFG.accent + '}',
      '.cc-cat strong{display:block;font-size:14px}',
      '.cc-cat span{display:block;color:' + muted + ';font-size:13px}',
      '@media(max-width:640px){.cc-bar .cc-card{display:block}.cc-bar .cc-actions{margin-top:14px}.cc-btn{flex:1 1 auto}}'
    ].join('');
    doc.head.appendChild(el);
  }

  function build() {
    var stored = read() || {};
    var root = doc.createElement('div');
    root.className = 'cc-root cc-' + CFG.position;
    root.setAttribute('role', CFG.position === 'modal' ? 'dialog' : 'region');
    root.setAttribute('aria-label', CFG.title);
    if (CFG.position === 'modal') root.setAttribute('aria-modal', 'true');

    var card = doc.createElement('div');
    card.className = 'cc-card';

    var copy = doc.createElement('div');
    var h = doc.createElement('p');
    h.className = 'cc-title';
    h.textContent = CFG.title;
    var p = doc.createElement('p');
    p.className = 'cc-text';
    p.textContent = CFG.message + ' ';
    if (CFG.policyUrl) {
      var link = doc.createElement('a');
      link.href = CFG.policyUrl;
      link.textContent = CFG.policyLabel;
      p.appendChild(link);
    }
    copy.appendChild(h);
    copy.appendChild(p);

    var cats = doc.createElement('div');
    cats.className = 'cc-cats';
    var inputs = {};
    for (var i = 0; i < CFG.categories.length; i++) {
      var c = CFG.categories[i];
      var row = doc.createElement('label');
      row.className = 'cc-cat';
      var cb = doc.createElement('input');
      cb.type = 'checkbox';
      cb.checked = c.required || stored[c.id] === true;
      cb.disabled = !!c.required;
      var txt = doc.createElement('div');
      var name = doc.createElement('strong');
      name.textContent = c.label;
      var desc = doc.createElement('span');
      desc.textContent = c.desc;
      txt.appendChild(name);
      txt.appendChild(desc);
      row.appendChild(cb);
      row.appendChild(txt);
      cats.appendChild(row);
      inputs[c.id] = cb;
    }
    copy.appendChild(cats);

    var actions = doc.createElement('div');
    actions.className = 'cc-actions';
    function button(label, main, onClick) {
      var b = doc.createElement('button');
      b.type = 'button';
      b.className = 'cc-btn' + (main ? ' cc-btn-main' : '');
      b.textContent = label;
      b.addEventListener('click', onClick);
      actions.appendChild(b);
      return b;
    }
    function decide(granted) {
      var consent = {};
      for (var i = 0; i < CFG.categories.length; i++) {
        var c = CFG.categories[i];
        consent[c.id] = c.required ? true : granted === null ? !!inputs[c.id].checked : granted;
      }
      save(consent);
      close();
    }
    var prefsBtn = button(CFG.prefs, false, function () {
      var open = cats.classList.toggle('cc-open');
      prefsBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
      saveBtn.style.display = open ? '' : 'none';
    });
    prefsBtn.setAttribute('aria-expanded', 'false');
    button(CFG.reject, false, function () { decide(false); });
    button(CFG.accept, true, function () { decide(true); });
    var saveBtn = button(CFG.save, false, function () { decide(null); });
    saveBtn.style.display = 'none';

    card.appendChild(copy);
    card.appendChild(actions);
    root.appendChild(card);
    doc.body.appendChild(root);
    box = root;
  }

  function close() {
    if (box && box.parentNode) box.parentNode.removeChild(box);
    box = null;
  }

  function open() {
    if (!box) build();
  }

  function start() {
    styles();
    var stored = read();
    if (stored) unblock(stored);
    else build();
    window.showConsentPreferences = open;
  }

  if (doc.readyState === 'loading') doc.addEventListener('DOMContentLoaded', start);
  else start();
})();
</script>

使い方

動くバナーまで3ステップ

1. スニペットを貼る

生成されたコードを、すべてのページで閉じるbodyタグの直前に置きます。依存関係はなく、ネットワークリクエストも増えません。

2. トラッキングスクリプトを待機させる

トラッキングタグのtypeをtext/plainに変え、data-consent="analytics"を追加します。バナーはそのカテゴリが許可された瞬間に実行し、それ以前には決して実行しません。

3. 後から変更できるようにする

window.showConsentPreferences()を呼び出すリンクをフッターに追加すれば、訪問者はパネルを開き直せます。選択のたびにconsentchangeイベントも発火するので、購読できます。

よくある質問

Cookie同意について

このバナーだけでGDPRに準拠できますか?

規制当局が求める仕組みは備えています。同意前に任意のCookieを置かない、拒否を許可と同じ手軽さにする、カテゴリごとに選べる、後から変更できる、という点です。ただし準拠は実際に何を実行しているか、ポリシーに何を書いているか、訪問者がどこにいるかにも左右されます。生成されたコードは法的助言ではなく、確かな出発点として扱ってください。

同意前にスクリプトが実行されないようにするには?

スクリプトタグに type="text/plain" と、カテゴリ名を指定した data-consent 属性を付けます。ブラウザはそれを実行せず、そのカテゴリが許可された時点でバナーが本物のスクリプトタグに書き換えます。今回の訪問でも、保存された選択に基づく次回の訪問でも同様です。

訪問者の選択はどこに保存されますか?

指定したキーのlocalStorageに、カテゴリごとのフラグと日付を持つ小さなJSONとして保存されます。バナー自体はCookieを設定せず、サーバーにも何も送らないため、完全な静的サイトでも動作します。

デザインは変更できますか?

はい。表示位置、テーマ、アクセントカラーはここで選べます。生成されるCSSの要素はすべてcc-で始まるため、スニペットに手を加えずに自分のスタイルシートから上書きできます。

同意管理プラットフォームはまだ必要ですか?

カテゴリが少ない1サイトなら、このスニペットで十分なことがほとんどです。同意ログ、複数ドメイン、選択を自動的に尊重する分析が必要になったら、PulsePandaに組み込まれた同意マネージャーがまるごと引き受けます。

関連

PulsePanda の関連情報

分析がきちんと尊重する同意

PulsePandaには同意マネージャーが標準搭載。既定でCookieを使わず、オプトアウトされた瞬間に収集を停止します。2つ目のベンダーも、つなぎのコードも不要です。

無料で始める