star back image
people4
電飾 電飾
moon
astronaut
EUの時にポップアップしたいGDPR対応

【GDPR】EUの時にポップアップしたい

BLOG WEBログWordPress
読了約:19分

トップページでCookieバナーを出していました。
GDPR対応って知ってますか?なんかいつも邪魔だなと感じるアレ。

何故つけたのですか。

確かEUの法律でcookieで広告が罰金で大変でアレだと言う。
そんな時期で自分も必要かなと思って付けました。

適当につけたことでずっと気になっていたのが以下の点です。

  • 日本ユーザーにも毎回出てしまう
  • とりあえず出しているだけ感でいっぱい

「ちゃんとやるならGDPR対応ツールを入れるべき」なのは理解しつつも、
個人サイトとしては 軽量・無料・壊れにくいラインに落としたいと考えました。

広告も入れてないブログですし、ライト版的な。

GDPRとは
General Data Protection Regulation(一般データ保護規則)の略です。

AIさんに教えてもらいました。EUではこう考えるそうです。
----
あなたの情報はあなたのもの
勝手に取るな、使うな
----

対象になる「個人データ」
・IPアドレス
・Cookie
・メールアドレス
・アクセス履歴

👉 Google Analyticsも対象
詳しくはAIに聞きましょう。

目指したのは、
👉 “それっぽく配慮しつつ、実用的に動く最小構成”
以下は完成図です。

AIに助けてもらったんですか。

はい。新しくなったチャッピーです。

共有ソースコード

あえて要件を絞っています。
※厳密なGDPR準拠ではなく、UI配慮ベース(推論に基づく設計)

  • EUっぽいユーザーだけ表示
  • 初回のみ表示(再訪問では出さない)
  • 同意するまで分析タグは動かさない
  • 同意後にのみ計測開始
  • 非EUユーザーには何も出さない
  • 外部APIは使わない(無料・軽量)
  • localStorage(cookieを使わない)

最初にGA + GTM 関係をコメントアウト

<!-- Google Tag Manager コメントアウト -->
<!--
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-●●●●●●●');</script>
-->

<!-- Google tag (gtag.js) コメントアウト -->
<!--
<script async src="https://www.googletagmanager.com/gtag/js?id=G-●●●●●●●●●●"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-●●●●●●●●●●');
</script>
-->

<!-- body直下の-->
<!-- Google Tag Manager (noscript) -->
<!--
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-P74VLK9"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
-->
<!-- End Google Tag Manager (noscript) -->

GA + GTM を拒否できるようにする仕様です。

HTML

<div class="cookie" id="cookie-banner">
  <div class="text-box">
    <p class="text">
      このWEBサイトでは、使いやすさの改善を目的にGoogleアナリティクスでCookieを利用しています。
      >> <a href="/privacy-policy/">プライバシーポリシー</a>
    </p>
  </div>
  <div class="btn-group" style="display: flex; gap: 10px;">
    <div class="btn" id="cookie-accept" style="cursor: pointer;">
      <p class="text">同意する</p>
    </div>
    <div class="btn" id="cookie-reject" style="cursor: pointer;">
      <p class="text">拒否</p>
    </div>
  </div>
</div>

CSS

/* 初期状態:非表示 */
.cookie {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transition: opacity 0.5s ease, visibility 0.5s ease !important;
}

/* クラス付与時:フェードイン表示 */
.cookie.is-visible {
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: auto !important;
}

Javascript

<script>
(function() {

  const STORAGE_KEY = 'cookieConsent';
  const GA_ID = 'G-●●●●●●●●●●';
  const GTM_ID = 'GTM-●●●●●●●';

  const consent = localStorage.getItem(STORAGE_KEY);

  // --- GA・GTM制御 ---
  function enableTracking() {
    // GA disable解除
    window['ga-disable-' + GA_ID] = false;

    // GA (gtag.js) ロード
    const s = document.createElement('script');
    s.src = 'https://www.googletagmanager.com/gtag/js?id=' + GA_ID;
    s.async = true;
    document.head.appendChild(s);

    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    window.gtag = gtag;

    gtag('js', new Date());
    gtag('config', GA_ID);

    // GTM (gtm.js) ロード
    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer',GTM_ID);
  }

  // 初期OFF
  window['ga-disable-' + GA_ID] = true;

  // 同意済み
  if (consent === 'accepted') {
    enableTracking();
    return;
  }

  // 拒否済み
  if (consent === 'denied') return;

  // --- バナー表示判定 ---
  const banner = document.getElementById('cookie-banner');

  function showBanner() {
    if (!banner) return;
    setTimeout(() => {
      banner.classList.add('is-visible');
    }, 300);
  }

  // 強制表示フラグ(is-euクラスがhtmlにある場合)
  const isForcedEU = document.documentElement.classList.contains('is-eu');

  // --- EU判定 + 表示実行 ---
  /* 【テスト用】常にバナーを表示させたい場合は、以下のブロックを有効(コメント解除)にしてください
  if (!consent) {
    showBanner();
  }
  */

  // 通常の判定ロジック(EU圏内のみ表示)
  if (!consent && !isForcedEU) {
    const lang = (navigator.language || '').toLowerCase();
    const tz = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
    
    // 日本なら即GA
    if (lang.startsWith('ja') || tz === 'Asia/Tokyo') {
      enableTracking();
    } else {
      const euTz = ['Europe/Paris','Europe/Berlin','Europe/Rome','Europe/Madrid','Europe/Amsterdam'];
      if (!euTz.includes(tz)) {
        enableTracking();
      } else {
        showBanner(); // EU圏ならバナー表示
      }
    }
  } else if (isForcedEU && !consent) {
    showBanner();
  }

  // --- ボタンリスナー(即時登録) ---
  const accept = document.getElementById('cookie-accept');
  const reject = document.getElementById('cookie-reject');

  if (accept) {
    accept.addEventListener('click', function() {
      localStorage.setItem(STORAGE_KEY, 'accepted');
      enableTracking();
      banner.classList.remove('is-visible');
      console.log('Accepted: Banner hidden');
    });
  }

  if (reject) {
    reject.addEventListener('click', function() {
      localStorage.setItem(STORAGE_KEY, 'denied');
      banner.classList.remove('is-visible');
      console.log('Denied: Banner hidden');
    });
  }

})();
</script>

EU判定の精度はどのくらいか気になりますよね。

EUユーザー 判定精度イメージ(簡易判定)

ユーザー判定
日本人(日本)❌ 出ない(ほぼ確実)
日本人(EU旅行中)✅ 出る
フランス人(EU)✅ 出る
アメリカ人(米国) ❌ 出ない
英語圏(EU在住)✅ 出る(タイムゾーンで拾う)
VPN利用⚠️ ブレる
言語を手動変更している人⚠️ ブレる可能性あり

動作確認の方法

EUでないと表示されません。
適用しても、どうやって確認したらいいのでしょうか。

ここは日本です。
以下はブラウザーのコンソールに、叩き込みますコードです。

UIの表示

localStorage.removeItem('cookieConsent'); // 初回状態に戻す
document.documentElement.classList.add('is-eu'); // EU強制
document.getElementById('cookie-banner').classList.add('is-visible'); // 表示

パッと出てきます。

ストレージ状態の確認

localStorage.getItem('cookieConsent');

accepted なら同意済み(保存されてる)
denied なら拒否済み(保存されてる)
null なら何も保存されてない(初回状態)

消してリロード

localStorage.removeItem('cookieConsent');
location.reload();

EUモードであれば、再表示されるハズ。

GAトラッキング確認(状態)

window['ga-disable-G-●●●●●●●●●●']

同意前 true / 同意後 false

という感じです。

WordPressのテンプレートに入れたい

2種のテンプレートを調整しましょう。

記事ページなどにも入れたいですよね。

header.php
→ GA + GTM 関係をコメントアウト。

footer.php
→ css、html、javascriptの追加。

これで全記事に挿入されます。

星間旅路のメロディ

「宇宙の静けさに包まれながら、漂流する過去の音楽を捜し求め、銀河の奥底でその旋律に耳を傾ける。」

「この電波はどこの星からきたのだろうか。」