DEV Community

Cover image for ติดตามผู้ใช้ข้ามเว็บไซต์ด้วย Tracking Pixel สำหรับ Web Developer
Passakon Puttasuwan
Passakon Puttasuwan

Posted on

ติดตามผู้ใช้ข้ามเว็บไซต์ด้วย Tracking Pixel สำหรับ Web Developer

สวัสดีเพื่อนๆ โปรแกรมเมอร์ทุกคน วันนี้ผมจะมาแชร์เรื่องการทำงานของ Tracking Pixel ฟีเจอร์ยอดฮิตในวงการ Web Analytics ที่หลายคนอาจเคยได้ยินชื่อ แต่ยังสงสัยว่ามันทำงานยังไง แล้วเราจะเขียนโค้ดยังไงให้ใช้มันเก็บข้อมูลผู้ใช้ได้อย่างแนบเนียน ไปดูกันเลย!

Tracking Pixel คืออะไร?

Tracking Pixel คือรูปภาพขนาดจิ๋ว (ขนาดแค่ 1x1 px) ที่ถูกฝังอยู่ในหน้าเว็บ มีลักษณะโปร่งใส มองไม่เห็นด้วยตาเปล่า แต่มีพลังในการเก็บข้อมูลผู้ใช้อย่างละเอียดยิบ ตั้งแต่ IP Address, อุปกรณ์ที่ใช้, ไปจนถึงพฤติกรรมการคลิก, การสกอร์ลเพจ และอีกสารพัด

แต่จะให้รูปภาพเก็บข้อมูลได้ยังไง? คำตอบคือมันไม่ได้ทำคนเดียว แต่ต้องอาศัย JavaScript ที่ถูกเขียนมาเพื่อส่งข้อมูลกลับไปที่เซิร์ฟเวอร์นั่นเอง พูดง่ายๆ ก็คือ รูปภาพเป็นแค่ Front แต่ JS ต่างหากที่เป็นตัวเก็บข้อมูลจริงๆ

ตัวอย่างการเขียนโค้ด Tracking Pixel

เรามาลองเขียนโค้ด Tracking Pixel อย่างง่ายที่เก็บอีเวนต์การคลิกกันนะ

<img src="https://www.example.com/pixel.gif?event=click" style="display:none;" />

<script>
document.addEventListener("click", function() {
  var img = document.createElement("img");
  img.src = "https://www.example.com/pixel.gif?event=click&timestamp=" + Date.now();
  img.style.display = "none";
  document.body.appendChild(img);
});
</script>
Enter fullscreen mode Exit fullscreen mode

จากโค้ดด้านบน เราสร้างแท็ก <img> ที่มี src เป็น URL ของรูปภาพพิกเซล และมีพารามิเตอร์ event เพิ่มเข้าไปเพื่อระบุว่าเป็นอีเวนต์คลิก

จากนั้นเราใช้ JavaScript ตรวจจับอีเวนต์คลิกผ่าน addEventListener เมื่อมีคลิกเกิดขึ้น เราจะสร้างแท็ก <img> ขึ้นมาใหม่แบบไดนามิก พร้อมแนบ timestamp ปัจจุบันเข้าไปใน URL เพื่อให้เซิร์ฟเวอร์รู้ว่าคลิกเกิดขึ้นเมื่อไหร่ แล้วซ่อนรูปนี้ไว้ (ไม่งั้นหน้าเว็บจะเต็มไปด้วยรูปพิกเซลแน่ๆ)

เท่านี้เราก็มี Tracking Pixel แบบง่ายๆ ที่สามารถเก็บอีเวนต์คลิกได้แล้ว!

ยิงข้อมูลไปเซิร์ฟเวอร์ภายนอก

บางครั้งเราอยากส่งข้อมูลไปให้บริการวิเคราะห์ภายนอกอย่าง Google Analytics ด้วย ซึ่งก็ไม่ยากเลย แค่เพิ่มโค้ดนิดหน่อยตามนี้

// ตรวจสอบว่ามี global ID ของ Analytics ไหม
var globalId = getUserIdFromCookie("_ga");

// ส่งข้อมูลไปเซิร์ฟเวอร์ของ Analytics
var data = {
  ...userData, 
  global_id: globalId,
  // เพิ่มข้อมูลอื่นๆ ที่อยากส่ง
};

var trackingUrl = "https://www.google-analytics.com/collect";
sendData(data, trackingUrl);
Enter fullscreen mode Exit fullscreen mode

จากโค้ดข้างบน เราเช็กว่าเว็บเราเคยถูกติดตั้ง Google Analytics ผ่านการหา ID ใน Cookie ไหม ถ้ามีก็ส่ง ID นั้นไปพร้อมกับข้อมูลอื่นๆ ผ่านฟังก์ชัน sendData ไปยัง URL ของ Analytics ซึ่งจะช่วยให้เราเชื่อมโยงข้อมูลจากเว็บเราเข้ากับข้อมูลอื่นๆ ในแพลตฟอร์มได้

ระบุตัวตนผู้ใช้ข้ามเว็บ

อีกเรื่องที่ท้าทายคือการระบุว่า ผู้ใช้ที่เข้ามาในเว็บเรา เคยเข้ามาเว็บอื่นที่เราติดตามด้วยไหม ซึ่งมีเทคนิคให้ใช้หลายอย่าง เช่น

  • Third-party Cookie: ใช้คุกกี้ที่ Set โดยโดเมนอื่นเพื่อเชื่อมข้อมูลข้ามเว็บ แต่อาจโดนเบราว์เซอร์ปัจจุบันบล็อก
  • ID ในลิงก์: แชร์ข้อมูลผู้ใช้ผ่าน ID บน URL ที่ลิงก์ข้ามเว็บ แต่ต้องให้เว็บอื่นร่วมมือด้วย
  • Deterministic: ใช้ข้อมูลส่วนตัวอย่างอีเมลหรือเบอร์โทรในการแมทช์ข้อมูลข้ามเว็บ แต่ต้องรอให้ผู้ใช้ล็อกอินก่อน
  • Probabilistic: ใช้ AI อนุมานตัวตนผู้ใช้จากข้อมูลหลายอย่าง แต่แม่นยำน้อยกว่า

ตัวอย่างการใช้ Local Storage เก็บ User ID ในเว็บเรา:

var userId = localStorage.getItem("user_id");

if (!userId) {
  userId = generateRandomId();
  localStorage.setItem("user_id", userId);
}

var userData = {
  user_id: userId,
  // ข้อมูลอื่นๆ
}
Enter fullscreen mode Exit fullscreen mode

โค้ดนี้จะเช็กว่าเคยมีการเก็บ User ID ใน Storage ไหม ถ้ายังก็สุ่มสร้างใหม่และเก็บไว้ ซึ่งจะใช้ระบุตัวตนผู้ใช้ได้จนกว่าเขาจะล้างข้อมูล

เรามาลองเขียนโค้ดที่เก็บข้อมูลผู้ใช้แบบละเอียดลึกซึ้งกว่าเดิมกันดีกว่า

จะได้เห็นภาพการทำงานของ Tracking Pixel ได้ชัดเจนขึ้น เริ่มจากเก็บข้อมูลพื้นฐานไปจนถึงข้อมูลพฤติกรรมเลยนะ

<script>
// ฟังก์ชันส่งข้อมูลไปเซิร์ฟเวอร์
function sendData(data) {
  var img = document.createElement("img");
  img.src = "https://www.mywebsite.com/track?" + objectToQueryString(data);
  img.style.display = "none";
  document.body.appendChild(img);
}

// แปลง Object เป็น Query String
function objectToQueryString(obj) {
  return Object.keys(obj).map(key => key + '=' + encodeURIComponent(obj[key])).join('&');
}

// เก็บข้อมูลพื้นฐานของผู้ใช้
var basicData = {
  user_id: localStorage.getItem("user_id") || generateRandomId(),
  session_id: sessionStorage.getItem("session_id") || generateRandomId(), 
  page_url: window.location.href,
  referrer: document.referrer,
  screen_resolution: window.screen.width + "x" + window.screen.height,
  user_agent: navigator.userAgent,
  timestamp: Date.now()
};

// เก็บ IDs ลง Storage
localStorage.setItem("user_id", basicData.user_id);
sessionStorage.setItem("session_id", basicData.session_id);

// ส่งข้อมูลเมื่อโหลดหน้า
window.addEventListener("load", function() {
  sendData({
    ...basicData,
    event_type: "page_view" 
  });
});

// ส่งข้อมูลเมื่อมีคลิก
document.addEventListener("click", function(event) {
  sendData({
    ...basicData,
    event_type: "click",
    target_tag: event.target.tagName,
    target_url: event.target.href || ""
  });
});

// ส่งข้อมูลเมื่อสกรอลเพจ
var scrollDepth = 0;
window.addEventListener("scroll", function() {
  var percentScrolled = Math.floor((window.scrollY / document.body.scrollHeight) * 100);
  if (percentScrolled > scrollDepth) {
    scrollDepth = percentScrolled;
    sendData({ 
      ...basicData,
      event_type: "scroll",
      scroll_depth: scrollDepth + "%"
    });
  }
});

// ส่งข้อมูลเมื่อ Focus Input
document.addEventListener("focusin", function(event) {
  if (event.target.tagName === "INPUT" || event.target.tagName === "TEXTAREA") {
    sendData({
      ...basicData,
      event_type: "input_focus",
      input_id: event.target.id,
      input_name: event.target.name
    });
  }
});

// ส่งข้อมูลเมื่อกรอกฟอร์มเสร็จ
document.addEventListener("submit", function(event) {
  var formData = new FormData(event.target);
  var entries = {};
  for(var pair of formData.entries()) {
    entries[pair[0]] = pair[1];
  }

  sendData({
    ...basicData,
    event_type: "form_submit",
    form_data: JSON.stringify(entries)
  });
});

// ส่งข้อมูลทุก 30 วินาที
setInterval(function() {
  sendData({
    ...basicData,
    event_type: "heartbeat",
    timestamp: Date.now()
  });
}, 30000);

</script>
Enter fullscreen mode Exit fullscreen mode

จากโค้ดด้านบน เราเก็บข้อมูลผู้ใช้แบบหลากหลายมากขึ้น ทั้งการ track แบบ active และ passive ดังนี้

  1. ข้อมูลพื้นฐาน อย่าง User ID, Session ID, URL ปัจจุบัน, หน้าที่มา, ความละเอียดจอ และ Timestamp โดยเราเก็บ ID ลง Storage เพื่อใช้ครั้งถัดไป

  2. การโหลดหน้า - เมื่อผู้ใช้โหลดหน้าเว็บ จะส่งข้อมูลประเภท "page_view" ไปที่เซิร์ฟเวอร์

  3. การคลิก - เมื่อมีการคลิกเกิดขึ้น จะส่งข้อมูลประเภทคลิก ป้ายกำกับของเป้าหมาย และ URL ของลิงก์ (ถ้ามี) ไป

  4. การสกรอลเพจ - เมื่อผู้ใช้เลื่อนหน้าเว็บ เราจะคำนวณเปอร์เซ็นต์ความลึกของการสกรอล และส่งข้อมูลกลับเมื่อมีการสกรอลลึกขึ้นกว่าเดิม

  5. การโฟกัสอินพุต - เมื่อผู้ใช้คลิกลงบนช่องกรอกข้อมูล <input> หรือ <textarea> จะส่งข้อมูลชื่อและ ID ของฟิลด์นั้นๆ ไป

  6. การส่งฟอร์ม - เมื่อผู้ใช้กด Submit ฟอร์ม จะเก็บข้อมูลจากฟิลด์ต่างๆ ในรูปแบบ JSON แล้วส่งไปพร้อมกับอีเวนต์ "form_submit"

  7. Heartbeat - ทุกๆ 30 วินาที จะส่ง Timestamp ล่าสุดเข้าไป เพื่อบอกว่าผู้ใช้ยังคงใช้งานหน้าเว็บอยู่ (แบบ Passive Tracking)

นอกจากนี้เรายังแปลงข้อมูลจาก Object ให้เป็น Query String ด้วยเมื่อส่งไปที่เซิร์ฟเวอร์ เพื่อให้อ่านค่าได้ง่าย

แน่นอนว่าข้อมูลที่เก็บได้ในตัวอย่างนี้ยังไม่ครบทุกอย่าง เรายังสามารถเก็บอะไรได้อีกเยอะ เช่น:

  • ตำแหน่งเมาส์ที่คลิก
  • การเปิดหรือปิดวิดีโอ
  • เวลาที่อยู่ในหน้าเว็บ
  • การพิมพ์ลงในฟิลด์ต่างๆ
  • ภาษาที่ตั้งค่าในเบราว์เซอร์
  • สถานะการเข้าสู่ระบบ
  • อื่นๆ อีกมากมาย

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

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

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

สุดท้ายนี้หวังว่าทุกคนจะได้ไอเดียการเขียน Tracking Pixel แบบครอบคลุม และเข้าใจถึงศักยภาพและข้อควรระวังในการใช้งานไปบ้างนะครับ ถ้ามีอะไรสงสัยเพิ่มเติมคอมเมนต์ถามได้เลย แล้วเจอกันใหม่บทความหน้า!

Top comments (0)