Team Digital

เว็บ React / Next.js นับ page_view ใน GA4 ไม่ครบ? สาเหตุจากเว็บ SPA และวิธีแก้ 3 แบบ

อ่าน 4 นาที
เว็บ React / Next.js นับ page_view ใน GA4 ไม่ครบ? สาเหตุจากเว็บ SPA และวิธีแก้ 3 แบบ
แชร์บทความนี้:FacebookPinterest

ใครทำเว็บด้วย React, Next.js, Vue หรือให้ AI ช่วยสร้างเว็บ แล้วติด Google Analytics 4 (GA4) ผ่าน Google Tag Manager (GTM) ไว้ ลองเช็คดูครับว่า GA4 นับ page_view ได้ครบทุกหน้าหรือเปล่า เพราะเว็บกลุ่มนี้ส่วนใหญ่เป็น "เว็บหน้าเดียว" (Single-Page Application หรือ SPA) เวลาเปลี่ยนหน้า เว็บไม่ได้โหลดหน้าใหม่จริงๆ ผลคือแท็กที่ติดไว้ใน GTM อาจไม่ทำงานเลย และ GA4 นับได้แค่หน้าแรกหน้าเดียว

สรุปสั้นๆ:

  1. เว็บ SPA เปลี่ยนหน้าโดยไม่โหลดหน้าใหม่ GTM จึงไม่เกิด Container Loaded, DOM Ready, Window Loaded ชุดใหม่
  2. ถ้าไม่ได้ตั้งค่าเพิ่ม GA4 จะได้ page_view แค่หน้าแรก และชื่อหน้า (page_title) ค้างอยู่ที่หน้าแรก
  3. แก้ได้ 3 วิธี: เปิด browser history events ใน Enhanced Measurement, ใช้ trigger History Change ใน GTM หรือให้เว็บ push event เข้า dataLayer
  4. เลือกใช้วิธีเดียว แล้วตรวจใน DebugView ว่าเปลี่ยนหน้า 1 ครั้งได้ page_view 1 ครั้งพอดี

เว็บทั่วไปกับเว็บ SPA เปลี่ยนหน้าต่างกันอย่างไร

เว็บทั่วไป (Multi-Page Application)

เว็บแบบดั้งเดิม เช่น เว็บที่ทำด้วย WordPress เวลาเรากดลิงก์ เบราว์เซอร์จะขอหน้าใหม่จาก Server แล้วโหลดใหม่ทั้งหน้า ทุกครั้งที่โหลดใหม่ GTM ก็โหลดใหม่ไปด้วย และเกิด event ชุดนี้ขึ้นมาใหม่ทุกหน้า

  • Container Loaded (gtm.js)
  • DOM Ready (gtm.dom)
  • Window Loaded (gtm.load)

แท็กที่ตั้ง trigger ไว้เป็น All Pages หรือ Page View จึงทำงานใหม่ทุกครั้งที่เปลี่ยนหน้า Google tag ก็ส่ง page_view ไปที่ GA4 ให้ทุกหน้าโดยอัตโนมัติ

Tag Assistant ของเว็บ WordPress แสดงหน้าแยกกันทุกครั้งที่เปลี่ยนหน้า พร้อม Container Loaded, DOM Ready, Window Loaded ครบทุกหน้า

เว็บ WordPress: กดเปลี่ยนหน้าแล้ว Tag Assistant ขึ้นหน้าใหม่แยกกันทางซ้าย (หน้าแรก, Blog, Contact) และแต่ละหน้ามี event ครบชุด (คลิกที่ภาพเพื่อดูขนาดเต็ม)

เว็บ SPA (Single-Page Application)

เว็บที่ทำด้วย React, Vue, Angular รวมถึง Next.js และ Nuxt ตอนเข้าเว็บครั้งแรกจะโหลดหน้าเหมือนเว็บทั่วไป แต่โหลดแค่ครั้งเดียว หลังจากนั้นกดไปหน้าไหน JavaScript จะเปลี่ยนแค่เนื้อหาในหน้า แล้วเปลี่ยน URL ด้วยคำสั่ง history.pushState() ให้ดูเหมือนเราไปหน้าใหม่แล้ว

ข้อดีคือเว็บเร็วมาก ไม่มีจังหวะหน้าจอขาว ใช้งานลื่นเหมือนแอป แต่เพราะหน้าไม่ได้โหลดใหม่ Container Loaded, DOM Ready, Window Loaded จึงไม่เกิดขึ้นอีก สำหรับ GTM ไม่ว่าผู้ใช้จะกดไปกี่หน้า ก็ยังนับว่าอยู่หน้าแรกหน้าเดียว

Tag Assistant ของเว็บ Next.js หลังกดเปลี่ยนหน้า มีแค่ Click และ Link Click ต่อท้ายหน้าเดิม ไม่มี Container Loaded ชุดใหม่

เว็บ Next.js: กดเมนูไปหน้าติดต่อเราแล้ว Tag Assistant ยังมีหน้าเดียว มีแค่ Click และ Link Click ต่อท้ายลงมา ชื่อหน้าด้านบนยังเป็นหน้าแรก (event content_group_update ในภาพคือ event ที่เว็บเราส่งเองสำหรับแก้ปัญหานี้ ดูวิธีที่ 3)

ผลเสียเมื่อเว็บ SPA ไม่ได้ตั้งค่าการนับ page_view

ภาพตัวอย่างต่อไปนี้มาจากเว็บ teamdigital.co ซึ่งทำด้วย Next.js โดยเราปิดแท็กที่แก้ปัญหานี้ไว้ชั่วคราวใน Workspace ทดสอบของ GTM เพื่อให้เห็นอาการที่เกิดขึ้นจริง

1. แท็กที่ใช้ trigger All Pages ไม่ทำงานหลังเปลี่ยนหน้า

หลังเปลี่ยนหน้า Tag Assistant ขึ้นว่า Tags Fired: None ไม่มีแท็กไหนทำงานเลยสักตัว ทั้ง GA4 และ Pixel โฆษณาที่ตั้ง trigger All Pages ไว้ทำงานแค่ตอนโหลดหน้าแรกครั้งเดียว

Tag Assistant แสดง Tags Fired: None หลังกดเปลี่ยนหน้าในเว็บ SPA

2. GA4 ได้ page_view แค่ครั้งเดียว

ใน DebugView ของ GA4 ตรง Top events มี page_view แค่ 1 ครั้ง ทั้งที่เปิดดูไปหลายหน้า เลื่อน timeline ดูก็มี page_view แค่ตอนเข้าเว็บครั้งแรก หลังจากนั้นว่างหมด ข้อมูลใน GA4 จึงเก็บได้แค่ว่าคนนี้ดูเว็บเราแค่หน้าเดียว

DebugView ของ GA4 แสดง page_view เพียง 1 ครั้ง แม้เปิดดูเว็บ SPA หลายหน้า

3. ชื่อหน้า (page_title) ค้างอยู่ที่หน้าแรก

คลิกดูรายละเอียดของ page_view ตรง page_title เป็นชื่อหน้าแรก และ event user_engagement ที่เกิดทีหลัง ตอนที่อยู่หน้าอื่นแล้ว ชื่อหน้าก็ยังเป็นหน้าแรกเหมือนเดิม

DebugView แสดง page_title ของ page_view และ user_engagement เป็นชื่อหน้าแรกเหมือนกัน แม้ผู้ใช้เปลี่ยนหน้าไปแล้ว

4. รายงาน GA4 เพี้ยนทั้งชุด

พอ page_view ขาดไป รายงานใน GA4 ก็เพี้ยนตามกันหมด

  • Pages and screens เห็นแต่หน้าแรกที่คนเข้ามา หน้าคอร์สหรือหน้าติดต่อเราเหมือนไม่มีใครเข้าเลย
  • เวลาที่คนใช้ในเว็บ ไปรวมอยู่ที่หน้าแรกหน้าเดียว
  • Path exploration และ Funnel ที่ใช้ดูว่าคนเข้ามาแล้วไปไหนต่อ จบอยู่ที่หน้าแรกทุกคน
  • Key event ที่สร้างจาก page_view เช่น นับ Conversion เมื่อมีคนเข้าหน้าขอบคุณ (/thank-you) จะไม่เกิด ถ้าเว็บพาไปหน้าขอบคุณแบบ SPA

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

เทียบกับเว็บทั่วไป

ใน DebugView ของเว็บ WordPress ได้ page_view ทุกครั้งที่เปลี่ยนหน้า คลิกดู page_title ก็เปลี่ยนตามหน้าที่เปิดจริงๆ ทั้งหน้าแรก หน้า Blog และหน้า Contact แบบนี้คือสิ่งที่ควรจะเป็น

DebugView ของเว็บ WordPress แสดง page_view 3 ครั้งตามจำนวนหน้าที่เปิด

วิธีเช็คว่าเว็บของคุณเป็น SPA หรือไม่

  1. ดูปุ่ม Refresh ของแท็บ: กดเมนูเปลี่ยนหน้าแล้ว ถ้าปุ่ม Refresh ไม่หมุนและหน้าจอไม่ขาวเลย มีโอกาสสูงว่าเป็น SPA
  2. ดูใน GTM Preview (Tag Assistant): กดลิงก์ไปหน้าอื่น ถ้าฝั่งซ้ายไม่มีหน้าใหม่ และไม่มี Container Loaded, DOM Ready, Window Loaded ชุดใหม่ แปลว่าเป็น SPA
  3. ดูใน DevTools: กด F12 ไปที่แท็บ Network เลือกฟิลเตอร์ Doc แล้วกดเปลี่ยนหน้า ถ้าไม่มี request เอกสาร HTML ใหม่ก็เป็น SPA
  4. ดูเครื่องมือที่ใช้ทำเว็บ: ติดตั้งส่วนขยาย Wappalyzer จะเห็นว่าเว็บใช้ React, Next.js, Vue หรือเครื่องมืออื่น

วิธีแก้ 3 แบบ ให้ GA4 นับ page_view ครบทุกหน้า

ทุกวิธีอาศัยหลักเดียวกัน คือเว็บ SPA เปลี่ยน URL ผ่าน History API (pushState) เราจึงต้องหาจังหวะนั้นแล้วส่ง page_view เพิ่มเอง

วิธีที่ 1: เปิด browser history events ใน Enhanced Measurement (ง่ายที่สุด)

  1. เข้า GA4 ไปที่ Admin > Data streams > เลือก Web stream ของเว็บ
  2. ที่ Enhanced measurement กดไอคอนเฟือง
  3. ที่ Page views กด Show advanced settings
  4. เปิด Page changes based on browser history events

GA4 จะส่ง page_view ทุกครั้งที่ URL เปลี่ยน ไม่ต้องตั้งอะไรใน GTM เพิ่ม ตัวเลือกนี้ปกติเปิดไว้อยู่แล้วตอนเปิด Page views ถ้าเช็คแล้วยังนับไม่ครบ ลองเข้าไปดูว่าถูกปิดไว้หรือเปล่า

ข้อควรระวัง: GA4 ส่ง page_view ทันทีที่ URL เปลี่ยน บางเว็บตอนนั้นชื่อหน้าใหม่ยังไม่ทันขึ้น ใน GA4 จึงอาจเห็น page_title เป็นของหน้าก่อนหน้า ให้ตรวจใน DebugView ทุกครั้ง

วิธีที่ 2: ใช้ trigger History Change ใน GTM

  1. ใน GTM ไปที่ Triggers > New > เลือกชนิด History Change
  2. สร้างแท็ก Google Analytics: GA4 Event ตั้ง Event Name เป็น page_view ใส่ Measurement ID ของ GA4 แล้วเลือก trigger History Change ที่สร้างไว้
  3. กด Preview ตรวจใน Tag Assistant และ DebugView แล้วค่อย Submit

วิธีนี้คุมได้มากกว่าวิธีที่ 1 เช่น เลือกเงื่อนไขได้ว่าจะยิงเฉพาะบางหน้า หรือใช้ตัวแปร Built-in กลุ่ม History (History Source, New History URL, Old History URL) กรองจังหวะที่ต้องการ แต่ยังมีปัญหาเรื่องจังหวะเหมือนวิธีแรก และบางเว็บเปลี่ยน URL ตอนกดฟิลเตอร์หรือเปลี่ยนแท็บด้วย ซึ่งอาจทำให้นับเกิน

ถ้าใช้วิธีนี้ ต้องปิด browser history events ในวิธีที่ 1 ด้วย ไม่งั้นจะนับซ้ำ

วิธีที่ 3: ให้เว็บ push event เข้า dataLayer (แม่นที่สุด)

วิธีนี้ต้องให้นักพัฒนาเว็บช่วย คือให้เว็บส่ง event เข้า dataLayer หลังเปลี่ยนหน้าเสร็จแล้วจริงๆ พร้อมข้อมูลของหน้าใหม่ ตัวอย่างสำหรับ Next.js (App Router)

"use client";

import { useEffect, useRef } from "react";
import { usePathname } from "next/navigation";

export default function SpaPageView() {
  const pathname = usePathname();
  const isFirstRender = useRef(true);

  useEffect(() => {
    // หน้าแรกนับไปแล้วจาก Google tag ตอนโหลดหน้า ข้ามรอบแรกเพื่อไม่ให้นับซ้ำ
    if (isFirstRender.current) {
      isFirstRender.current = false;
      return;
    }
    // รอให้ URL บนแถบที่อยู่เปลี่ยนเป็นหน้าใหม่ก่อน (สูงสุดประมาณ 20 เฟรม) ไม่งั้น page_location จะเป็นของหน้าก่อนหน้า
    let frame = 0;
    let handle = 0;
    const push = () => {
      if (window.location.pathname !== pathname && frame < 20) {
        frame += 1;
        handle = requestAnimationFrame(push);
        return;
      }
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: "virtual_page_view",
        page_location: window.location.href,
        page_title: document.title,
      });
    };
    push();
    return () => cancelAnimationFrame(handle);
  }, [pathname]);

  return null;
}

จากนั้นตั้งค่าใน GTM

  1. สร้าง Data Layer Variable ชื่อ DLV - page_location และ DLV - page_title
  2. สร้าง trigger ชนิด Custom Event ตั้ง Event name เป็น virtual_page_view
  3. สร้างแท็ก GA4 Event ตั้ง Event Name เป็น page_view เพิ่ม Event Parameter page_location = {{DLV - page_location}} และ page_title = {{DLV - page_title}} แล้วเลือก trigger จากข้อ 2

ข้อดีคือเราเลือกจังหวะยิงเองได้ ให้ยิงหลังหน้าใหม่ขึ้นครบแล้ว ชื่อหน้า URL และข้อมูลเสริมอย่าง Content Group จึงส่งไปถูกต้อง

จุดที่ต้องระวังที่สุด: ถ้า push เร็วเกินไป เนื้อหาและชื่อหน้าเปลี่ยนแล้ว แต่ URL บนแถบที่อยู่ยังเป็นของหน้าเก่า page_location ที่ส่งไปจะเป็นของหน้าก่อนหน้า ทั้งที่ page_title ถูกต้อง รายงานที่ดูตาม Page path จะเพี้ยนไป 1 หน้าทุกครั้ง โค้ดตัวอย่างข้างบนจึงรอให้ URL เปลี่ยนก่อนค่อย push และหลังติดตั้งต้องเปิด GTM Preview กดเปลี่ยนหน้า แล้วดูที่แท็ก page_view ทุกครั้งว่าทั้ง page_location และ page_title เป็นของหน้าใหม่

ตัวอย่างจากเว็บ Team Digital: ทุกครั้งที่เปลี่ยนหน้า เว็บจะส่ง event ชื่อ content_group_update เข้า dataLayer พร้อม Content Group ของหน้าใหม่ (event เดียวกับที่เห็นในภาพ Tag Assistant ด้านบน) แล้วใน GTM เราสร้างแท็ก GA4 Event ชื่อ page_view ที่ใช้ event นี้เป็น trigger ผลคือเปลี่ยนหน้า 1 ครั้ง GA4 ได้ page_view 1 ครั้ง พร้อม Content Group ของหน้านั้น ชื่อ event จะตั้งเป็นอะไรก็ได้ ขอแค่ให้ชื่อใน dataLayer กับใน trigger ของ GTM ตรงกัน

ถ้าใช้วิธีนี้ ต้องปิด browser history events ในวิธีที่ 1 และไม่ใช้ trigger History Change ในวิธีที่ 2 ซ้ำ

ข้อควรระวัง: อย่าใช้หลายวิธีพร้อมกัน

  • เลือกวิธีเดียว: ถ้าเปิดหลายวิธีพร้อมกัน page_view จะถูกนับซ้ำ 2-3 ครั้งต่อการเปลี่ยนหน้า ตัวเลขดูสวยแต่ไม่ใช่ของจริง
  • ทดสอบทุกครั้ง: กดเปลี่ยนหน้า 3 ครั้ง ใน DebugView ต้องเห็น page_view 3 ครั้งพอดี ไม่ใช่ 1 หรือ 6 และทั้ง page_title และ page_location ต้องเป็นของหน้าที่เปิดอยู่ ไม่ใช่หน้าก่อนหน้า
  • อย่าลืม Pixel โฆษณา: Meta Pixel ปกติจะส่ง PageView เองเมื่อ URL เปลี่ยน ถ้าไปเพิ่ม trigger เปลี่ยนหน้าใน GTM ให้แท็ก PageView ของ Pixel ซ้ำอีกอาจนับซ้ำ ตรวจได้ด้วยส่วนขยาย Meta Pixel Helper ส่วน Pixel อื่นอย่าง TikTok Pixel หรือ LINE Tag ที่ตั้ง trigger All Pages ไว้ ต้องตรวจทีละตัวว่าทำงานตอนเปลี่ยนหน้าหรือไม่

สรุป

ถ้าเว็บของคุณทำด้วย React, Next.js หรือ Vue เวลาเปลี่ยนหน้าจะไม่มีการโหลดหน้าใหม่ GTM จึงไม่เห็น Container Loaded, DOM Ready, Window Loaded ชุดใหม่ GA4 ได้ page_view แค่หน้าแรก และชื่อหน้าค้างอยู่ที่หน้าแรกตลอด ผลคือรายงานว่าคนดูหน้าไหน อยู่นานแค่ไหน และไปไหนต่อ เพี้ยนหมด

แก้ได้ด้วยการเลือกใช้ 1 ใน 3 วิธีข้างบน แล้วตรวจใน DebugView ให้เปลี่ยนหน้า 1 ครั้งได้ page_view 1 ครั้งพอดี ถ้ายังไม่เคยติดตั้ง GA4 ผ่าน GTM เริ่มได้จากบทความ การติดตั้ง Google Tag Manager บนเว็บไซต์ และ การสร้างและติดตั้ง Google Analytics 4 บนเว็บไซต์

แชร์บทความนี้:FacebookPinterest

อยากตั้งค่า GA4 และ GTM ให้เก็บข้อมูลถูกต้องตั้งแต่แรก

เรียนรู้การติดตั้ง GA4 ด้วย Google Tag Manager ตั้งค่า Event และ Conversion พร้อมตรวจข้อมูลใน DebugView จาก Workshop ติดตั้งจริง

ใน คอร์สเรียน Google Analytics 4 อบรมแบบเจาะลึก 2 วัน สอนโดย อ.ศรัณย์ ยุวรรณะ (อ.หนุ่ย)

ดูรายละเอียดคอร์ส Google Analytics 4

Team Digital จัดหลักสูตรอบรมการตลาดออนไลน์และเอไอ อบรมแบบกลุ่มเล็ก ดูแลทั่วถึง เช่น หลักสูตรอบรม Digital Marketing, หลักสูตรอบรม Shopee/Lazada, หลักสูตรอบรม SEO, หลักสูตรอบรม Google Ads, หลักสูตรเรียนยิงแอด Facebook, คอร์สสอน LINE OA, หลักสูตร YouTuber, คอร์สสอน Google Analytics 4, หลักสูตรอบรม WordPress, คอร์สสอน TikTok, คอร์สสอน Gemini Deep Research & NotebookLM และ หลักสูตรอบรม Power BI รวมทั้งยังรับจัดหลักสูตรอบรมภายในองค์กร (In-House Training) ให้กับหน่วยงานและองค์กรต่างๆ

About The Author

ศรัณย์ ยุวรรณะ
อ.ศรัณย์ ยุวรรณะ

อ.หนุ่ย Co-founder ของ Team Digital ผู้เชี่ยวชาญและนักเขียนด้านการตลาดดิจิทัล วิทยากรหลักสูตร Advanced Digital Marketing, Google Analytics 4 (GA4), LINE Official Account (LINE OA) ปัจจุบันใช้ AI พัฒนาระบบธุรกิจของตัวเอง

สอบถาม/จองคอร์ส