EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Web / แบนเนอร์คุกกี้ที่กั้นได้จริง โหลด GTM กับ GA4 หลังกดยอมรับเท่านั้น
Web

แบนเนอร์คุกกี้ที่กั้นได้จริง โหลด GTM กับ GA4 หลังกดยอมรับเท่านั้น

โดย Ton-Or ·18 ต.ค. 2026·อ่าน 9 นาที
แบนเนอร์คุกกี้ที่กั้นได้จริง โหลด GTM กับ GA4 หลังกดยอมรับเท่านั้น

แบนเนอร์คุกกี้ที่ขึ้นมาตอนโหลดหน้าเสร็จ ทั้งที่สคริปต์เก็บข้อมูลวิ่งไปหมดแล้วตั้งแต่บรรทัดแรก มีค่าเท่ากับป้ายประกาศ ไม่ใช่ระบบขอความยินยอม ความต่างของสองอย่างนี้อยู่ที่ลำดับการโหลดไม่กี่บรรทัด แต่เป็นไม่กี่บรรทัดที่ตัดสินว่าเว็บเราทำตามที่เขียนไว้ในหน้านโยบายหรือเปล่า

พอดีผมทำเว็บที่มีทั้ง Google Tag Manager, GA4 และ AdSense อยู่ด้วยกัน แล้วต้องขึ้นแบนเนอร์คุกกี้ตามที่เขียนไว้ในหน้านโยบาย ระหว่างไล่ดูของที่ทำไว้เดิมก็เจอว่าแบนเนอร์มันขึ้นจริง ปุ่มกดได้จริง เก็บค่าไว้จริง แต่ถ้าเปิดแท็บ Network ดูตอนที่แบนเนอร์ยังค้างอยู่บนจอ จะเห็นว่า container ของ GTM โหลดไปเรียบร้อยแล้ว GA4 ยิง collect ไปแล้วหนึ่งนัด ทั้งที่ผู้ใช้ยังไม่ได้แตะปุ่มอะไรเลย ผมเลยรื้อใหม่ทั้งชุด

ค่า ID ทุกตัวในบทความเป็นค่าตัวอย่าง ให้เปลี่ยนเป็นของตัวเองก่อนใช้งาน ส่วนโครงกับลำดับการโหลดคือของจริงที่ใช้อยู่

ปัญหา: แบนเนอร์ที่ไม่ได้กั้นอะไรเลย

โค้ดที่เจอบ่อยที่สุดคือแบบนี้ คือเอาสคริปต์มาตรฐานที่ Google ให้มาวางไว้บนสุดของ <head> ตามคู่มือ แล้วค่อยเขียนแบนเนอร์แยกไว้อีกไฟล์

<!-- แบบที่เจอบ่อย และไม่ได้กั้นอะไรเลย -->
<head>
  <!-- GTM โหลดทันทีที่หน้าเริ่มพาร์ส -->
  <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);j.async=true;
  j.src='https://www.googletagmanager.com/gtm.js?id='+i;f.parentNode.insertBefore(j,f);
  })(window,document,'script','dataLayer','GTM-XXXXXXX');</script>

  <!-- GA4 โหลดตรงอีกตัว ซ้ำกับที่ตั้งไว้ใน GTM -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
</head>
<body>
  <div id="cookie-bar">เว็บนี้ใช้คุกกี้ <button>ยอมรับ</button></div>
</body>

ตรงนี้มีปัญหาสองชั้นซ้อนกัน ชั้นแรกคือความยินยอมถูกขอหลังจากเก็บข้อมูลไปแล้ว ซึ่งขัดกับหลักที่เรียกว่า prior consent ตรง ๆ ชั้นที่สองคือ GA4 ถูกโหลดสองทาง ทั้งจาก tag ที่ตั้งไว้ใน GTM และจากบรรทัด gtag/js ที่วางไว้เอง ผลคือยอดผู้เข้าชมถูกนับซ้ำโดยที่ไม่มีใครสังเกต เพราะตัวเลขมันดูสวยขึ้น

แบนเนอร์ไม่ได้ทำให้เว็บทำตามนโยบาย โค้ดต่างหากที่ทำ

สิ่งที่ตรวจสอบได้จริงมีอย่างเดียวคือ จำนวน request ที่ออกไปหาปลายทาง ก่อนที่ผู้ใช้จะกดยอมรับ ถ้าเลขนั้นไม่ใช่ศูนย์ แบนเนอร์สวยแค่ไหน ข้อความยาวแค่ไหน ก็ไม่มีความหมาย ตัวเลขนี้ใครก็เปิด DevTools ดูได้ในสิบวินาที รวมถึงคนที่ตั้งใจจะมาหาเรื่องเราด้วย

เลือกทางก่อนลงมือ: กั้นทั้ง container หรือใช้ consent mode

มีสองทางที่ใช้กันจริงและทั้งคู่ใช้ได้ ต่างกันที่ระดับความเข้ม

ทางแรกคือ consent mode คือยังโหลด GTM ตามปกติ แต่ประกาศสถานะเริ่มต้นเป็นปฏิเสธไว้ก่อน แล้วอัปเดตเมื่อผู้ใช้กดยอมรับ ข้อดีคือได้ข้อมูลแบบไม่ระบุตัวตนตั้งแต่ก่อนกดยอมรับ และแท็กหลายตัวรองรับอยู่แล้ว

// ทางที่หนึ่ง: consent mode — ยังโหลด GTM แต่ประกาศสถานะเริ่มต้นไว้ก่อน
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('consent', 'default', {
  ad_storage: 'denied',
  ad_user_data: 'denied',
  ad_personalization: 'denied',
  analytics_storage: 'denied',
  wait_for_update: 500,
});
// ...เมื่อผู้ใช้กดยอมรับ
gtag('consent', 'update', { ad_storage: 'granted', analytics_storage: 'granted' });

ทางที่สองคือไม่โหลด container เลยจนกว่าจะกดยอมรับ ข้อเสียคือเสียข้อมูลช่วงก่อนกด และเสียความสามารถบางอย่างของ consent mode ไป ข้อดีคือมันตรวจสอบได้ด้วยตาเปล่า เปิด Network ดู ถ้าไม่มี request ออกไปเลยก็จบ ไม่ต้องไปเชื่อว่าสคริปต์ปลายทางเคารพธงที่เราตั้งไว้จริงหรือเปล่า

ส่วนตัวผมเลือกทางที่สองเป็นหลักครับ เพราะเว็บที่ผมดูแลไม่ได้ทำการตลาดแบบยิงแอดที่ต้องพึ่งข้อมูลช่วงก่อนยินยอม การเสียข้อมูลไปนิดหน่อยแลกกับข้อพิสูจน์ที่ชัดเจนว่าไม่มีอะไรออกไปนั้นคุ้มกว่ามาก ใครที่ต้องพึ่งข้อมูลแอดจริงจังก็เลือกทางแรกได้ตามสะดวก แต่ต้องยอมรับว่าต้องไล่ตรวจแต่ละแท็กเองว่าเคารพธงหรือเปล่า

สามช่วงเวลา เทียบแบบเดิมกับแบบกั้นด้วยการกดยอมรับหน้าเริ่มโหลดแบนเนอร์ค้างบนจอหลังกดยอมรับแบบเดิมGTM โหลดทันทีgtag/js โหลดซ้ำอีกตัวGA4 ยิง collect แล้วผู้ใช้ยังไม่แตะปุ่มยอดผู้เข้าชมนับซ้ำGA4 มาสองทางแบบกั้นไม่มี request ออกสถานะ nullโชว์แบนเนอร์request = 0โหลด gtm.js 1 ครั้งGA4 อยู่ใน GTM ตัวเดียวตัวตรวจ: ก่อนกด 0 request และ gtm.js หลังโหลดซ้ำ = 1 ครั้ง
แถวบนคือโค้ดแบบเดิม แถวล่างคือโครงที่โหลด container เมื่อกดยอมรับเท่านั้น
consent mode

โหลดก่อน แล้วบอกว่าห้ามเก็บ

  • ได้ข้อมูลแบบไม่ระบุตัวตนก่อนกด
  • แท็กในระบบเดียวกันรองรับเอง
  • พิสูจน์ยาก ต้องเชื่อปลายทาง
  • เหมาะกับเว็บที่พึ่งข้อมูลแอด
กั้นทั้ง container

ไม่โหลดจนกว่าจะกด

  • ก่อนกดไม่มี request ออกเลย
  • พิสูจน์ได้ด้วย Network หรือสคริปต์
  • เสียข้อมูลช่วงก่อนกดทั้งหมด
  • เหมาะกับเว็บเนื้อหาที่รัน AdSense

สามสถานะที่ต้องออกแบบให้ครบ

คนมักออกแบบแค่สองสถานะคือยังไม่กด กับกดยอมรับแล้ว แล้วลืมสถานะที่สาม คือ กดปฏิเสธไปแล้ว ซึ่งต้องไม่ถามซ้ำทุกครั้งที่เปลี่ยนหน้า ไม่งั้นผู้ใช้จะรำคาญจนไปกดยอมรับเพื่อให้มันหายไป ซึ่งนั่นไม่ใช่ความยินยอมที่ได้มาโดยสมัครใจ

สามสถานะยังไม่เลือกค่าเป็น null->โชว์แบนเนอร์ไม่โหลดอะไร->กดยอมรับโหลด GTM หนึ่งครั้ง
เส้นทางปฏิเสธกดปฏิเสธบันทึกว่า declined->ซ่อนแบนเนอร์ถาวรไม่ถามซ้ำ->ซ่อนช่องโฆษณาเว็บใช้งานได้ปกติ->เหลือปุ่มที่ท้ายเว็บเปลี่ยนใจได้เอง

แบนเนอร์: ปุ่มสองปุ่มต้องเท่ากัน

เรื่องหน้าตามีข้อเดียวที่ผมถือว่าสำคัญคือปุ่มยอมรับกับปฏิเสธต้องมีน้ำหนักเท่ากัน ขนาดเท่ากัน อ่านง่ายเท่ากัน การทำปุ่มปฏิเสธให้เป็นตัวหนังสือจาง ๆ เล็ก ๆ มุมล่าง คือการออกแบบให้คนกดผิด และมันทำให้ความยินยอมที่ได้มาไม่มีน้ำหนัก

<!-- วางท้าย body — ไม่ต้องรีบ ไม่ต้องบล็อกการเรนเดอร์ -->
<div id="ck-bar" class="ck-bar" hidden role="dialog" aria-label="การใช้คุกกี้">
  <p class="ck-txt">เว็บนี้ใช้คุกกี้เพื่อวัดผลการใช้งานและแสดงโฆษณา
     ถ้ายังไม่ยอมรับ เว็บยังใช้งานได้ตามปกติทุกส่วน
     <a href="/privacy">อ่านนโยบายความเป็นส่วนตัว</a></p>
  <div class="ck-act">
    <button type="button" id="ck-no"  class="ck-btn">ปฏิเสธ</button>
    <button type="button" id="ck-yes" class="ck-btn ck-primary">ยอมรับ</button>
  </div>
</div>
.ck-bar{position:fixed;left:0;right:0;bottom:0;z-index:9999;display:flex;gap:16px;
        align-items:center;flex-wrap:wrap;padding:16px 20px;
        background:#17130e;color:#f1ece0;font-size:.92rem;line-height:1.7}
.ck-txt{margin:0;flex:1 1 320px}
.ck-txt a{color:#f3713f}
.ck-act{display:flex;gap:10px;flex:0 0 auto}
/* ปุ่มสองปุ่มขนาดเท่ากัน อ่านง่ายเท่ากัน */
.ck-btn{min-width:128px;padding:11px 18px;border:1px solid #f1ece0;border-radius:2px;
        background:transparent;color:#f1ece0;font-size:.92rem;cursor:pointer}
.ck-primary{background:#e5330b;border-color:#e5330b;color:#fff}
@media (max-width:480px){.ck-act{width:100%}.ck-btn{flex:1 1 0}}

แกนกลาง: ตัวโหลด GTM ที่เรียกซ้ำไม่ได้

หัวใจอยู่ที่ตรงนี้ครับ สคริปต์ของ GTM ต้องอยู่ในฟังก์ชัน และฟังก์ชันนั้นต้องถูกเรียกจากทางเดียวคือเมื่อสถานะเป็นยอมรับเท่านั้น พร้อมตัวกันเรียกซ้ำ เพราะถ้าโหลด container สองรอบ dataLayer จะถูก process ซ้ำและยอดจะเพี้ยน

// consent.js — ทั้งหมดของการกั้นอยู่ในไฟล์นี้ไฟล์เดียว
(function () {
  'use strict';

  var KEY = 'ck_consent';          // accepted | declined | (ไม่มีค่า = ยังไม่เลือก)
  var GTM_ID = 'GTM-XXXXXXX';      // เปลี่ยนเป็นของตัวเอง
  var loaded = false;

  function readState() {
    try { return localStorage.getItem(KEY); } catch (e) { return null; }
  }
  function writeState(v) {
    try { localStorage.setItem(KEY, v); } catch (e) { /* โหมดส่วนตัว เขียนไม่ได้ ไม่ต้องพัง */ }
  }

  function loadGTM() {
    if (loaded) return;            // กันเรียกซ้ำ สำคัญมาก
    loaded = true;
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({ 'gtm.start': Date.now(), event: 'gtm.js' });
    var j = document.createElement('script');
    j.async = true;
    j.src = 'https://www.googletagmanager.com/gtm.js?id=' + GTM_ID;
    document.head.appendChild(j);
  }

  function accept() {
    writeState('accepted');
    hideBar();
    document.documentElement.classList.remove('ck-noads');
    loadGTM();
    showAds();
  }

  function decline() {
    writeState('declined');
    hideBar();                     // ไม่โหลดอะไรทั้งนั้น ช่องโฆษณายังซ่อนอยู่
  }

  function hideBar() { var b = document.getElementById('ck-bar'); if (b) b.hidden = true; }
  function showBar() {
    var b = document.getElementById('ck-bar');
    if (!b) return;
    b.hidden = false;
    document.getElementById('ck-yes').addEventListener('click', accept);
    document.getElementById('ck-no').addEventListener('click', decline);
  }

  var state = readState();
  if (state !== 'accepted') document.documentElement.classList.add('ck-noads');
  if (state === 'accepted') { loadGTM(); showAds(); }
  else if (state === null)  { document.addEventListener('DOMContentLoaded', showBar); }

  window.ckManage = function () {  // ให้ปุ่มท้ายเว็บเรียกเพื่อเปลี่ยนใจ
    try { localStorage.removeItem(KEY); } catch (e) {}
    location.reload();
  };
})();
localStorage เขียนไม่ได้ในบางโหมด ต้องครอบ try ทุกครั้ง

ในหน้าต่างส่วนตัวของบางเบราว์เซอร์ หรือเมื่อผู้ใช้ตั้งค่าบล็อกข้อมูลเว็บไซต์ไว้ คำสั่ง localStorage.setItem จะโยน error ออกมา ไม่ได้คืนค่า false ถ้าไม่ครอบ try ไว้ ปุ่มยอมรับจะกดแล้วไม่มีอะไรเกิดขึ้นเลยเพราะสคริปต์ตายก่อนถึงบรรทัดโหลด GTM และเส้นทางที่จำค่าไม่ได้ต้องยังใช้งานได้ คือถามใหม่รอบหน้า ไม่ใช่หน้าพัง

GA4 ต้องเป็นแท็กข้างใน GTM และตั้งใจไม่ใส่ noscript

ถ้าจะใช้ GTM แล้ว ให้ตั้ง GA4 เป็น tag ข้างใน container ไปเลย อย่าไปวาง gtag/js คู่ไว้ในหน้าอีกตัว เพราะมันคือการยิงสองทางไปหาปลายทางเดียวกัน ยอดจะเกินจริงและหาสาเหตุยากมากเวลาตัวเลขไม่ตรงกับความรู้สึก

// ถ้ามีอีเวนต์ของเราเอง ให้ push เข้า dataLayer แล้วให้ GTM เป็นคนตัดสินใจส่งต่อ
function track(name, params) {
  if (!window.dataLayer) return;              // ยังไม่ยอมรับ ก็ไม่มี dataLayer ให้ push
  window.dataLayer.push(Object.assign({ event: name }, params || {}));
}
// ตัวอย่าง: track('form_submit', { form_id: 'contact' });
// GA4 config อยู่ใน GTM ตัวเดียว ไม่มี gtag/js ในหน้าอีกแล้ว

อีกเรื่องที่ผมตั้งใจไม่ใส่คือ noscript iframe ที่คู่มือของ GTM ให้มาวางไว้ต้น <body>

<!-- ตัวนี้ผมตั้งใจไม่ใส่ เพราะมันทำงานนอกเหนือการควบคุมของ JS ทั้งหมด -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>

เหตุผลตรงไปตรงมาครับ ตัวกั้นทั้งหมดของเราเป็น JavaScript ถ้าผู้ใช้ปิด JavaScript แบนเนอร์ก็ไม่ขึ้น ปุ่มก็กดไม่ได้ แต่ iframe ตัวนี้ยังโหลดตามปกติ กลายเป็นว่าคนที่ระวังตัวที่สุดคือคนที่โดนเก็บข้อมูลโดยไม่มีโอกาสปฏิเสธเลย ที่เสียไปคือข้อมูลของผู้ใช้กลุ่มที่ปิด JavaScript ซึ่งน้อยมากอยู่แล้ว เทียบกับการเปิดช่องโหว่ที่ตรวจแล้วอธิบายไม่ได้ ผมเลือกไม่ใส่

AdSense: ซ่อนช่องไว้ก่อน แล้วค่อย push ตอนยอมรับ

เว็บที่รันโฆษณามีเงื่อนไขเพิ่มอีกชั้น คือช่อง <ins class="adsbygoogle"> ถูกวางไว้ในหน้าตั้งแต่แรก ถ้าไม่ทำอะไรเลย มันจะเป็นกล่องว่างค้างอยู่กลางเนื้อหาระหว่างที่ยังไม่ยอมรับ วิธีที่ผมใช้คือซ่อนด้วย CSS ที่ผูกกับ class บน <html> แล้วปลดตอนยอมรับ

/* ซ่อนช่องโฆษณาตราบใดที่ยังไม่ได้รับความยินยอม — ไม่ให้เหลือช่องว่างในเนื้อหา */
html.ck-noads .adsbygoogle,
html.ck-noads .ad-slot { display: none !important; }
// ส่วนของ AdSense ใน consent.js — เรียกจาก accept() เท่านั้น
var ADS_CLIENT = 'ca-pub-XXXXXXXXXXXXXXXX';   // เปลี่ยนเป็นของตัวเอง
var adsLoaded = false;

function showAds() {
  if (adsLoaded) return;
  adsLoaded = true;

  var s = document.createElement('script');
  s.async = true;
  s.crossOrigin = 'anonymous';
  s.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' + ADS_CLIENT;
  s.onload = function () {
    // สั่งเรนเดอร์ช่องที่มีอยู่แล้วในหน้า หนึ่ง push ต่อหนึ่งช่อง
    var slots = document.querySelectorAll('.adsbygoogle:not([data-adsbygoogle-status])');
    for (var i = 0; i < slots.length; i++) {
      try { (window.adsbygoogle = window.adsbygoogle || []).push({}); } catch (e) {}
    }
  };
  document.head.appendChild(s);
}
push ต้องนับตามช่องที่ยังไม่ถูกเรนเดอร์

ตัวเลือก .adsbygoogle:not([data-adsbygoogle-status]) สำคัญกว่าที่คิด เพราะช่องที่สคริปต์เรนเดอร์ไปแล้วจะมีแอตทริบิวต์นั้นติดอยู่ ถ้าไปนับรวมแล้ว push เกินจำนวนช่องจริง จะได้ error ว่า All ins elements already have ads in them ในคอนโซล ซึ่งไม่ทำให้หน้าพัง แต่มันกลบ error ตัวอื่นที่สำคัญกว่าจนอ่านคอนโซลไม่รู้เรื่อง

ตรวจด้วยเบราว์เซอร์จริง: request ปลายทางต้องเป็นศูนย์

ทั้งหมดที่เขียนมาจะเชื่อถือได้ก็ต่อเมื่อมีตัวเลขยืนยัน ผมเขียนตัวตรวจที่เปิดหน้าเว็บ ดักทุก request แล้วนับเฉพาะที่วิ่งไปหาโดเมนปลายทางของ GTM, GA4 และ AdSense ต้องได้ศูนย์ก่อนกด และต้องมากกว่าศูนย์หลังกดยอมรับ

// tools/consent-check.cjs — ด่านที่ตอบว่าแบนเนอร์กั้นได้จริงหรือเปล่า
const { chromium } = require('playwright');

const WATCH = ['googletagmanager.com', 'google-analytics.com', 'analytics.google.com',
               'googlesyndication.com', 'doubleclick.net'];
const hits = [];

(async () => {
  const b = await chromium.launch();
  const p = await b.newPage();
  p.on('request', r => { if (WATCH.some(d => r.url().includes(d))) hits.push(r.url()); });

  await p.goto('https://example.com/?v=' + Date.now(), { waitUntil: 'networkidle' });
  await p.waitForTimeout(2500);

  const before = hits.length;
  console.log(`[${before === 0 ? 'OK' : 'FAIL'}] ก่อนกดยอมรับ: ${before} request`);
  hits.forEach(u => console.log('       ', u));

  const bar = await p.$('#ck-bar:not([hidden])');
  console.log(`[${bar ? 'OK' : 'FAIL'}] แบนเนอร์แสดงอยู่`);

  await p.click('#ck-yes');
  await p.waitForTimeout(3000);
  const after = hits.length - before;
  console.log(`[${after > 0 ? 'OK' : 'FAIL'}] หลังกดยอมรับ: ${after} request`);

  // กดยอมรับแล้วโหลดใหม่ ต้องไม่ถามซ้ำ และต้องไม่โหลด container ซ้ำซ้อน
  const mark = hits.length;
  await p.reload({ waitUntil: 'networkidle' });
  await p.waitForTimeout(2000);
  const gtm = hits.slice(mark).filter(u => u.includes('gtm.js')).length;
  console.log(`[${gtm === 1 ? 'OK' : 'FAIL'}] โหลดซ้ำหน้าเดิม: gtm.js = ${gtm} ครั้ง`);

  await b.close();
  process.exit(before === 0 && after > 0 && gtm === 1 ? 0 : 1);
})();
$ node tools/consent-check.cjs
[OK] ก่อนกดยอมรับ: 0 request
[OK] แบนเนอร์แสดงอยู่
[OK] หลังกดยอมรับ: 7 request
[OK] โหลดซ้ำหน้าเดิม: gtm.js = 1 ครั้ง

บรรทัดสุดท้ายคือตัวที่ผมเพิ่มทีหลังหลังจากเผลอเรียก loadGTM() สองที่ในโค้ดเวอร์ชันก่อน แล้วยอดผู้เข้าชมสูงเป็นสองเท่าอยู่สามวัน ตัวกันเรียกซ้ำในฟังก์ชันช่วยได้ก็จริง แต่ตัวตรวจที่นับให้เห็นเป็นตัวเลขดีกว่าการเชื่อว่าเราเขียนกันไว้แล้ว

ถอนความยินยอมได้ และสรุปเป็นขั้นตอน

ข้อสุดท้ายที่คนลืมกันบ่อยคือคนที่กดไปแล้วต้องเปลี่ยนใจได้ ถ้าไม่มีทางกลับ ก็เท่ากับถามครั้งเดียวตลอดชีวิต ผมวางปุ่มเล็ก ๆ ไว้ที่ท้ายเว็บทุกหน้า

<!-- ท้ายเว็บ ข้าง ๆ ลิงก์นโยบาย -->
<button type="button" class="foot-link" onclick="ckManage()">จัดการคุกกี้</button>
0request ก่อนกดยอมรับ
1 ครั้งโหลด gtm.js ต่อหนึ่งหน้า
3สถานะที่ออกแบบไว้
128 pxความกว้างขั้นต่ำของปุ่ม
0 ตัวnoscript iframe ที่ใส่
5 โดเมนปลายทางที่ตัวตรวจเฝ้า
4 ด่านที่ตัวตรวจต้องผ่าน
3 วันที่ยอดเคยเกินสองเท่า
  1. เอาสคริปต์ GTM และ GA4 ออกจาก <head> ให้หมด ย้ายเข้าไปอยู่ในฟังก์ชัน loadGTM()
  2. ตั้ง GA4 เป็น tag ข้างใน container ตัวเดียว อย่าวาง gtag/js คู่ไว้ในหน้าอีก
  3. ออกแบบให้ครบสามสถานะ และอย่าถามซ้ำกับคนที่กดปฏิเสธไปแล้ว
  4. ทำปุ่มยอมรับกับปฏิเสธให้มีน้ำหนักเท่ากัน ทั้งขนาดและความชัด
  5. ซ่อนช่องโฆษณาด้วย class บน <html> ระหว่างที่ยังไม่ยอมรับ แล้ว push ตามจำนวนช่องที่ยังไม่ถูกเรนเดอร์
  6. ครอบทุกการอ่านเขียน localStorage ด้วย try และให้เส้นทางที่จำค่าไม่ได้ยังใช้งานเว็บได้ปกติ
  7. รันตัวตรวจที่นับ request ปลายทาง ต้องได้ศูนย์ก่อนกด และ gtm.js ต้องเท่ากับหนึ่งต่อหนึ่งหน้า
  8. วางปุ่มจัดการคุกกี้ไว้ท้ายเว็บทุกหน้า ให้คนเปลี่ยนใจได้เอง

เรื่องนี้ผมมองว่าไม่ใช่งานตามกฎอย่างเดียวนะครับ มันเป็นเรื่องที่ตรวจสอบได้ด้วยเครื่องมือที่ใครก็มี ใครจะเปิด DevTools ดูเว็บเราตอนไหนก็ได้ และสิ่งที่เขาเห็นจะตรงกับที่เราเขียนไว้ในหน้านโยบายหรือไม่ตรง มันมีคำตอบเดียว ส่วนจะเลือกทาง consent mode หรือกั้นทั้ง container ก็ดูจากว่าเว็บตัวเองพึ่งข้อมูลช่วงก่อนยินยอมแค่ไหน ตามสะดวกครับ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

อยากให้เราทำให้ไหม?

ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า

คุยเรื่องงานกับเรา

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย