เบอร์เดียวกัน แต่แฮชได้คนละค่า จุดพลาดของการ Normalize ข้อมูลไทยก่อนแฮชส่งเข้า CAPI

สรุปสั้น ๆ
SHA-256 เป็นฟังก์ชันที่ตรงไปตรงมา แต่ input ก่อนแฮชต่างหากที่เป็นจุดพลาดบ่อยที่สุด เบอร์โทรและอีเมลของคนไทยมีรูปแบบหลากหลายกว่าที่คิด ถ้า normalize ไม่ตรงตามสเปกของแต่ละแพลตฟอร์ม แฮชจะออกมาคนละค่าทุกครั้งแม้จะเป็นคนเดียวกัน
มีทีมหนึ่งที่ผมช่วยตรวจโค้ดให้ เขาบ่นว่า match quality บน Meta ตกต่ำผิดปกติ ทั้งที่ hash เบอร์โทรกับอีเมลไปหมดทุก event แล้ว ผมขอดู log การแฮชจริง ๆ พบว่าปัญหาไม่ได้อยู่ที่ตัวฟังก์ชัน SHA-256 เลย แต่อยู่ที่ข้อมูลก่อนแฮช ลูกค้าคนเดียวกันบางออเดอร์เก็บเบอร์เป็น 0812345678 บางออเดอร์เก็บเป็น 081-234-5678 บางออเดอร์เก็บเป็น +66812345678 ทั้งสามค่านี้ผ่าน SHA-256 แล้วได้ hash คนละค่ากันหมด ทั้งที่เป็นเบอร์เดียวกันเป๊ะ
นี่คือความเข้าใจผิดที่พบบ่อยในทีมพัฒนา คือคิดว่าเรื่องแฮชจบแค่ ‘เรียกฟังก์ชัน SHA-256’ แล้วส่งไป แต่ความจริงแพลตฟอร์มโฆษณาทุกเจ้าคาดหวังว่า input ก่อนแฮชต้องผ่านการทำความสะอาดตามสเปกที่กำหนดไว้ก่อน ถ้าทำไม่ตรง hash จะไม่มีวันตรงกับที่แพลตฟอร์มมีอยู่ในระบบของเขา ต่อให้เป็นข้อมูลถูกต้อง 100% ก็ตาม
บทความนี้จะเจาะกฎ normalize ที่ต้องรู้เป็นพิเศษเมื่อทำงานกับข้อมูลไทย เพราะเบอร์โทรและชื่อของคนไทยมีลักษณะเฉพาะที่สเปกทั่วไปของแพลตฟอร์มไม่ได้พูดถึงตรง ๆ
กับดักเบอร์โทรไทย: 0 นำหน้า vs +66 vs ช่องว่างที่มองไม่เห็น
เบอร์โทรไทยมาตรฐานคือ 10 หลักขึ้นต้นด้วย 0 แต่รูปแบบสากลที่แพลตฟอร์มโฆษณาส่วนใหญ่คาดหวังคือรูปแบบ E.164 ซึ่งต้องตัด 0 นำหน้าออกแล้วใส่รหัสประเทศ +66 แทน นั่นแปลว่า 0812345678 ต้องกลายเป็น 66812345678 ก่อนแฮช (ไม่มีเครื่องหมายบวก ไม่มีช่องว่าง) ถ้าระบบของคุณเก็บเบอร์แบบ 0812345678 ตรง ๆ แล้วแฮชเลยโดยไม่แปลง จะไม่มีวันจับคู่กับข้อมูลที่แพลตฟอร์มมีอยู่ได้เลย
ปัญหาที่ซ่อนอยู่ลึกกว่านั้นคือ แหล่งข้อมูลลูกค้าที่มาจากหลายช่องทางมักเก็บเบอร์คนละรูปแบบ แบบฟอร์มเว็บอาจเก็บ 081-234-5678 แอดมินพิมพ์มือใน CRM อาจเผลอเว้นวรรค หรือมีเลข 0 ซ้ำสองตัวจากการ copy-paste ผิด ทุกความต่างเล็ก ๆ เหล่านี้ทำให้แฮชออกมาคนละค่า ต้องมีขั้นตอน strip อักขระที่ไม่ใช่ตัวเลขออกทั้งหมดก่อน แล้วค่อยเช็กว่าขึ้นต้นด้วย 0 หรือ 66 แล้วแปลงให้เป็นรูปแบบเดียวกันเสมอ
อีเมล: ตัวพิมพ์เล็ก-ใหญ่ และช่องว่างหัวท้ายที่คนมักลืม
กฎของอีเมลดูเหมือนง่ายกว่าเบอร์โทร แต่จุดพลาดที่เจอบ่อยคือลืมแปลงเป็นตัวพิมพ์เล็กทั้งหมดก่อนแฮช เพราะ Somchai@Gmail.com กับ somchai@gmail.com คือกล่องเมลเดียวกันในทางปฏิบัติ แต่ SHA-256 มองว่าเป็นสตริงคนละตัวและให้ hash คนละค่า ถ้าฟอร์มลูกค้าอนุญาตให้พิมพ์ตัวพิมพ์ใหญ่ได้อิสระ (ซึ่งเบราว์เซอร์ส่วนใหญ่ก็ไม่บังคับ) ต้องมีขั้นตอน lowercase บังคับในโค้ดฝั่งเซิร์ฟเวอร์เสมอ อย่าไว้ใจว่าฝั่ง frontend ทำให้แล้ว
อีกจุดที่มองข้ามคือช่องว่างที่แฝงมากับการ copy-paste จากแอปแชท เวลาแอดมินคัดลอกอีเมลจากข้อความ LINE มาวางใน CRM บางครั้งจะติดช่องว่างที่มองไม่เห็นมาด้วย (เช่น zero-width space หรือ trailing space) ต้อง trim ทั้งหัวและท้ายสตริงก่อนแฮชเสมอ ไม่ใช่แค่ trim ช่องว่างธรรมดาที่มองเห็นด้วยตา
ชื่อ-นามสกุลคนไทย: ทำไมจับคู่ได้ยากกว่าประเทศอื่น
บางแพลตฟอร์มรับ hash ของชื่อ-นามสกุลเป็นสัญญาณเสริมเพื่อยกระดับการจับคู่ แต่ชื่อคนไทยมีความหลากหลายของการสะกดมากกว่าภาษาอังกฤษมาก คำเดียวกันสะกดได้หลายแบบ (เช่น สมชาย vs สมไชย ในบางกรณีเป็นคนละครอบครัวสะกดต่างกันจริง) และคนไทยมักใช้ชื่อเล่นในการทักแชทแทนชื่อจริงในเอกสาร ทำให้ signal จากชื่อมีความน่าเชื่อถือต่ำกว่าเบอร์โทรและอีเมลมาก
คำแนะนำที่ใช้ได้จริงคือ อย่าพึ่งชื่อเป็น signal หลักเพียงอย่างเดียว ให้ใช้เป็น signal เสริมที่ส่งไปพร้อมกับเบอร์โทรหรืออีเมลเสมอ และถ้าจะ normalize ชื่อ อย่างน้อยต้อง trim ช่องว่างและลบคำนำหน้าอย่าง นาย นาง นางสาว ออกให้สม่ำเสมอ เพราะบางระบบเก็บคำนำหน้าปนมากับชื่อ บางระบบแยกเป็นคอลัมน์ต่างหาก ความไม่สม่ำเสมอตรงนี้ก็ทำให้แฮชไม่ตรงกันได้เหมือนกัน
แต่ละแพลตฟอร์มสเปกไม่เหมือนกันเป๊ะ ต้อง normalize แยกชุด
| แพลตฟอร์ม | รูปแบบเบอร์ที่คาด | หมายเหตุอีเมล |
|---|---|---|
| Meta CAPI | E.164 ไม่มีเครื่องหมาย + | lowercase และ trim ก่อนแฮชเสมอ |
| Google Enhanced Conversions | E.164 มีเครื่องหมาย + นำหน้า | lowercase เหมือนกัน แต่ trailing dot ในโดเมนต้องระวังเป็นพิเศษ |
| TikTok Events API | ตัวเลขล้วนไม่มีเครื่องหมายใด ๆ | รองรับทั้ง SHA-256 แบบ hex และแบบไม่ hash ในบาง endpoint ต้องอ่าน spec ให้ตรงเวอร์ชัน |
วาง pipeline normalize ให้เป็นขั้นตอนเดียวที่ใช้ร่วมกันทุกแพลตฟอร์ม
วิธีที่ทำให้ดูแลง่ายในระยะยาวคือ อย่าเขียนโค้ด normalize แยกกันในแต่ละจุดที่เรียกใช้ ให้มีฟังก์ชันกลางที่รับข้อมูลดิบเข้ามาแล้วคืนค่ารูปแบบมาตรฐานออกไป แล้วค่อยมีชั้นบาง ๆ ต่อจากนั้นที่ปรับรูปแบบให้ตรงสเปกของแต่ละแพลตฟอร์มอีกที เพราะถ้าแก้ไข logic normalize กระจายอยู่หลายจุด วันหนึ่งที่พบบั๊กจะแก้ไม่ครบทุกจุดและปัญหาจะกลับมาใหม่
ทีมที่ทำเรื่องนี้ได้ดีมักมี test suite เล็ก ๆ ที่ป้อนเบอร์โทรและอีเมลรูปแบบแปลก ๆ ที่เจอจริงจากข้อมูลลูกค้า (ไม่ใช่แค่เคสสวย ๆ ในเอกสาร) แล้วเช็กว่าผลลัพธ์ normalize ตรงกับที่คาดหวังเสมอ เพราะการไล่ดีบัก match quality ที่ตกต่ำในภายหลังจะยากขึ้นมากถ้าไม่มีจุดตรวจสอบตั้งแต่ตอนเขียนโค้ด
สรุป
ปัญหา match quality ต่ำที่หลายทีมโทษว่าแพลตฟอร์มโฆษณา ‘ไม่แม่น’ ส่วนใหญ่จริง ๆ แล้วเกิดจากข้อมูลก่อนแฮชในระบบตัวเองไม่สม่ำเสมอ ซึ่งเป็นเรื่องที่แก้ได้ด้วยโค้ดไม่กี่บรรทัด แต่ต้องรู้ก่อนว่าจุดที่ต้องแก้อยู่ตรงไหน
ถ้าทีมคุณยังไม่เคยเขียน test suite ทดสอบการ normalize เบอร์โทรและอีเมลรูปแบบแปลก ๆ ที่เจอจริงในฐานข้อมูล นี่คืองานที่ควรทำก่อนไปปรับจูนเรื่องอื่น เพราะต้นทางสะอาด ปลายทางถึงจะแม่นตามไปด้วย
- เบอร์โทรไทยต้องแปลงเป็น E.164 (66xxxxxxxxx) ก่อนแฮชเสมอ ไม่ใช่ 0xxxxxxxxx
- อีเมลต้อง lowercase และ trim ช่องว่างที่มองไม่เห็นก่อนแฮชทุกครั้ง
- แต่ละแพลตฟอร์มมีสเปก normalize ต่างกันเล็กน้อย ต้องแยกชั้นแปลงข้อมูลตามปลายทาง
คำถามที่พบบ่อย
ต้อง normalize ก่อนแฮชทุกครั้งไหม หรือแฮชแล้วค่อยแก้ทีหลังได้
ต้อง normalize ก่อนแฮชเสมอ เพราะ hash เป็นฟังก์ชันทางเดียว ย้อนกลับไปแก้ไขค่าที่แฮชไปแล้วไม่ได้ ถ้าพลาดตรงนี้ต้องไปแก้ที่ต้นทางแล้วแฮชใหม่ทั้งหมด
ใช้ SHA-256 เหมือนกันหมดทุกแพลตฟอร์มได้ไหม
อัลกอริทึมแฮชส่วนใหญ่ใช้ SHA-256 เหมือนกัน แต่รูปแบบข้อมูลก่อนแฮชต่างกันตามที่แต่ละแพลตฟอร์มกำหนด จึงต้องมีขั้นตอน normalize แยกตามสเปกของแต่ละเจ้าแม้จะใช้ฟังก์ชันแฮชตัวเดียวกันก็ตาม
ถ้าฐานข้อมูลลูกค้าเก่ามีเบอร์หลายรูปแบบปนกันอยู่แล้ว ต้องแก้ยังไง
แนะนำให้เขียนสคริปต์ normalize ข้อมูลเก่าทั้งหมดให้เป็นรูปแบบมาตรฐานเดียวกันก่อน แล้วบันทึกทับในฐานข้อมูล เพื่อให้ทุก event ในอนาคตเริ่มจากข้อมูลสะอาดตั้งแต่ต้น ไม่ต้อง normalize ซ้ำทุกครั้งที่ดึงมาใช้
เบอร์มือถือกับเบอร์บ้านต้อง normalize ต่างกันไหม
หลักการ normalize เหมือนกัน (แปลงเป็น E.164) แต่ควรพิจารณาไม่ส่งเบอร์บ้านเป็น phone matching key เพราะแพลตฟอร์มส่วนใหญ่ผูกเบอร์กับบัญชีผู้ใช้รายบุคคล เบอร์บ้านมักจับคู่ไม่ติดและเสียเวลาประมวลผลเปล่า ๆ
แฮชผิดรูปแบบแล้วส่งเข้า CAPI จะเกิดอะไรขึ้น ระบบ error ไหม
ส่วนใหญ่ไม่ error เพราะแพลตฟอร์มไม่รู้ว่า hash ที่ส่งมาถูก normalize มาถูกต้องหรือเปล่า มันแค่จับคู่ไม่ติดเงียบ ๆ แล้วปล่อยให้ match quality ต่ำลงเรื่อย ๆ โดยไม่มีข้อความแจ้งเตือนใด ๆ ทำให้ปัญหานี้ตรวจจับยากกว่า error ทั่วไป
ควรเก็บข้อมูลดิบ (ก่อนแฮช) ไว้นานแค่ไหน เพื่อ debug ย้อนหลัง
เก็บได้ตามนโยบายความเป็นส่วนตัวและ<a href="/blog/hash-email-phone-capi-line">แนวทางการแฮชข้อมูลก่อนส่ง</a>ที่ทีมกำหนดไว้ แต่ควรมีอย่างน้อยช่วงสั้น ๆ ที่ทีมพัฒนาเข้าถึงได้แบบจำกัดสิทธิ์ เพื่อไล่ debug กรณี match quality ตกผิดปกติ ไม่ใช่เก็บไว้ตลอดไปโดยไม่มีเหตุผล
อ่านต่อแบบเจาะลึก
รู้ว่าโฆษณาเข้า LINE ทำยอดขายจริงแค่ไหน
linli ติดตามลูกค้าตั้งแต่คลิกโฆษณา กดเพิ่มเพื่อน ทักแชท จนปิดการขาย พร้อมส่ง Conversion กลับแพลตฟอร์มโฆษณา เริ่มฟรี 14 วัน
ทดลองใช้ฟรี 14 วันบทความที่เกี่ยวข้อง

คะแนน Event Match Quality ร่วงจาก 7.2 เหลือ 4.8 ในคืนเดียว วาง Diagnostic Workflow ไล่หาสาเหตุแบบไม่เดาสุ่ม

ลูกค้าทักไลน์วันจันทร์ โอนเงินจริงวันพฤหัส หน้าต่างเวลาที่แพลตฟอร์มยอมรับ Conversion ย้อนหลังนานแค่ไหน
