การขอความยินยอมคุกกี้สำหรับ Next.js, Gatsby และ Static Site: คู่มือการเชื่อมต่อสำหรับนักพัฒนา

ปัญหาการขอความยินยอมบน Static Site

เฟรมเวิร์ก JavaScript สมัยใหม่อย่าง Next.js, Gatsby และ Nuxt.js ได้เปลี่ยนวิธีการสร้างและส่งมอบหน้าเว็บไปอย่างสิ้นเชิง หน้าเว็บจะถูก prerender ตอน build time หรือบนเซิร์ฟเวอร์ แล้วจึงถูกhydrate บนฝั่ง client สิ่งนี้สร้างความท้าทายเฉพาะสำหรับการขอความยินยอมค���กกี้: แบนเนอร์ขอความยินยอมต้องพร้อมก่อนที่สคริปต์ติดตามใด ๆ จะทำงาน แต่ตัวหน้าเพจอาจถูกเรนเดอร์และแคชไว้ที่ edge แล้ว

CMP แบบดั้งเดิมถูกออกแบบมาสำหรับหน้า PHP ที่เรนเดอร์บนเซิร์ฟเวอร์หรือหน้า HTML แบบง่าย ๆ ที่โหลดเอกสารจากบนลงล่างอย่างเป็นลำดับ ในโลกของเฟรมเวิร์กที่มี code splitting, lazy loading และการเรนเดอร์ฝั่งเซิร์ฟเวอร์แบบสตรีมมิง สมมติฐานเหล่านั้นใช้ไม่ได้อีกต่อไป การตั้งค่าการขอความยินยอมให้ถูกต้องในสภาพแวดล้อมเหล่านี้จำเป็นต้องเข้าใจกระบวนการเรนเดอร์ให้ดี

ทำไมเรื่องเวลา (Timing) ถึงสำคัญกว่าที่คิด

ในหน้า HTML ปกติ การวางสคริปต์ CMP ไว้ใน <head> ก่อนสคริปต์อื่น ๆ เป็นเรื่องตรงไปตรงมา แต่ใน Next.js App Router หรือ Gatsby สถานการณ์ซับซ้อนกว่านั้น:

หลักการสำคัญคือ: ต้องจัดการ consent ในระดับสคริปต์ ไม่ใช่ระดับคอมโพเนนต์ React component ที่เรนเดอร์แบนเนอร์ขอความยินยอมจะช้าเกินไป หากมันกลายเป็น interactive ได้ก็ต่อเมื่อการ hydrate เสร็จแล้วเท่านั้น

การเชื่อมต่อกับ Next.js App Router

Next.js 13+ ที่มาพร้อม App Router มีวิธีจัดการสคริปต์รูปแบบใหม่ วิธีที่แนะนำสำหรับการเชื่อมต่อระบบขอความยินยอมมีดังนี้:

ขั้นตอนที่ 1: โหลดสคริปต์ CMP ใน Root Layout

ใช้คอมโพเนนต์ Script ของ Next.js พร้อมกลยุทธ์ beforeInteractive ในไฟล์ layout.tsx ระดับ root วิธีนี้จะบอก Next.js ให้ inject สคริปต์เข้าไปในเอกสาร HTML แรกก่อนที่การ hydrate จะเริ่ม:

กลยุทธ์ beforeInteractive มีความสำคัญอย่างยิ่ง กลยุทธ์เริ่มต้น afterInteractive จะโหลดสคริปต์หลังจากการ hydrate ซึ่งช้าเกินไปสำหรับการขอความยินยอม ด้วย beforeInteractive สคริปต์ CMP จะถูกใส่ใน HTML ที่เรนเดอร์จากเซิร์ฟเวอร์และทำงานในขณะที่หน้าโหลด

ขั้นตอนที่ 2: ตั้งค่า Default Consent ก่อน Google Tag

ก่อนสคริปต์ Google Tag Manager หรือ gtag.js ให้ใส่ inline script ที่ตั้งค่าสถานะ consent เริ่มต้น วิธีนี้ทำให้มั่นใจได้ว่าแม้ GTM จะโหลดก่อนที่แบนเนอร์ CMP จะปรากฏ มันก็ยังเคารพค่าปฏิเสธเริ่มต้นเหล่านั้น:

inline script นี้ควรถูกวางไว้ใน <head> ของ root layout ก่อนสคริปต์ CMP และ GTM ใน Next.js คุณสามารถใช้แท็ก <script> ปกติภายใน element <head> ของ layout เพื่อจุดประสงค์นี้

ขั้นตอนที่ 3: จัดการการเปลี่ยนเส้นทาง (Route Changes)

ในการนำทางแบบ single-page application สคริปต์ CMP จะโหลดเพียงครั้งเดียว แต่การเปลี่ยน route จะไม่ทำให้หน้าโหลดใหม่ทั้งหน้า CMP ของคุณจึงต้องคงอยู่ตลอดการนำทางฝั่ง client FlexyConsent จัดการเรื่องนี้ให้อัตโนมัติ — เมื่อโหลดแล้ว มันจะยังคงทำงานอยู่ในทุกการเปลี่ยน route โดยไม่ต้อง initialize ใหม่

การเชื่อมต่อกับ Next.js Pages Router

สำหรับโปรเจกต์ที่ยังใช้ Pages Router วิธีการจะคล้ายกันแต่ใช้ _document.tsx แทน root layout ให้วางสคริปต์ CMP ไว้ในคอมโพเนนต์ <Head> ของ custom Document class กลยุทธ์ beforeInteractive ใช้งานได้แบบเดียวกันใน Pages Router

ความแตกต่างสำคัญคือ _document.tsx จะเรนเดอร์บนเซิร์ฟเวอร์เท่านั้น ดังนั้นลอจิกการขอความยินยอมใด ๆ ที่อยู่ในนี้จะถูกใส่ใน HTML แรกที่ถูกส่งออกไปอย่างแน่นอน

การเชื่อมต่อกับ Gatsby Static Site

Gatsby จะสร้าง HTML แบบ static เต็มรูปแบบตอน build time ไม่มีการเรนเดอร์ฝั่งเซิร์ฟเวอร์ในตอน request ซึ่งทำให้บางอย่างง่ายขึ้นแต่ก็ทำให้บางอย่างซับซ้อนขึ้น:

แนวทาง build-time ของ Gatsby ทำให้ทุกไฟล์ HTML บน CDN ของคุณมีสคริปต์ consent อยู่ด้วย ซึ่งจริง ๆ แล้วถือว่าเหมาะมาก — ไม่มีลอจิกฝั่งเซิร์ฟเวอร์ให้ล้มเหลวหรือแคชผิดพลาด

ประเด็นที่ต้องคำนึงถึงใน Nuxt.js

Nuxt.js (พื้นฐานคือ Vue) มีรูปแบบของตัวเอง ใน Nuxt 3 ให้ใช้ composable useHead หรือการตั้งค่า app head ใน nuxt.config.ts เพื่อเพิ่มสคริปต์ CMP แบบ global Nuxt รองรับออปชัน body: false (ซึ่งจะวางสคริปต์ใน head) และแอตทริบิวต์ async สำหรับการโหลดแบบไม่บล็อกการเรนเดอร์

สำหรับโหมด server-side rendering ของ Nuxt หลักการเดียวกันยังใช้ได้: สคริปต์ CMP ต้องอยู่ใน HTML ตอบกลับแรก ไม่ใช่ถูก inject แบบไดนามิกโดย Vue component หลังจาก mount แล้ว

การหลีกเลี่ยง Layout Shift

แบนเนอร์ขอความยินยอมมักเป็นตัวการของ Cumulative Layout Shift (CLS) ซึ่งเป็น Core Web Vital ที่มีผลต่ออันดับ SEO เมื่อแบนเนอร์โผล��ขึ้นมาหลังจากหน้าเรนเดอร์แล้ว มันจะดันเนื้อหาลงหรือซ้อนทับเนื้อหาอย่างไม่คาดคิด

กลยุทธ์เพื่อลด CLS จากแบนเนอร์ขอความยินยอม:

แนวทางที่ไม่ผูกกับเฟรมเวิร์กของ FlexyConsent

FlexyConsent ถูกออกแบบมาให้ทำงานร่วมกับเฟรมเวิร์กใดก็ได้ — หรือแม้แต่ไม่มีเฟรมเวิร์กเลย — โดยทำงานในระดับสคริปต์แทนระดับคอมโพเนนต์ เหตุผลที่เรื่องนี้สำคัญ��ีดังนี้:

เคล็ดลับสำหรับนักพัฒนา: วิธีทดสอบที่ง่ายที่สุดว่าคุณเชื่อมต่อ CMP ได้ถูกต้องหรือไม่ คือเปิดแท็บ Network ในเบราว์เซอร์ กรองด้วยโดเมนของ Google แล้วรีโหลดหน้า ห้ามมี request ไปยัง Google ใด ๆ เกิดขึ้นก่อนที่คำสั่งตั้งค่า consent เริ่มต้นจะปรากฏใน console หากมี แสดงว่า CMP ของคุณโหลดช้าเกินไป

แพ็กเกจฟรีของ FlexyConsent รองรับจำนวน pageview ไม่จำกัด และทำงานร่วมกับ Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix และ HTML ธรรมด��� การเชื่อมต่อเหมือนกันทั้งหมด: ใช้เพียงแท็กสคริปต์เดียว วางให้ถูกที่

← บล็อก อ่านทั้งหมด →