เบอร์เดียวกัน แต่แฮชได้คนละค่า: จุดพลาดของการ 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 ตกผิดปกติ ไม่ใช่เก็บไว้ตลอดไปโดยไม่มีเหตุผล
บทความที่เกี่ยวข้อง


