Mở đầu — vì sao bài này quan trọng
Ở Bài 7, bạn đã học các nguyên tắc thiết kế event taxonomy — cách đặt tên event, cách chọn cấu trúc, cách tránh loạn tên. Nhưng một event tên đẹp mà "rỗng ruột" thì cũng vô dụng. Câu hỏi thực sự quyết định giá trị của dữ liệu là: mỗi event mang theo những thông tin gì? Đó chính là payload — phần "nội dung" đi kèm mỗi event khi nó được gửi lên Mixpanel hay Amplitude.
Hãy tưởng tượng bạn là PM của một sàn thương mại điện tử. Bạn có event product_viewed được bắn hàng triệu lần mỗi ngày. Nếu event đó chỉ có tên mà không kèm theo product_id, category, price, source thì sáu tháng sau, khi sếp hỏi "khách xem nhiều sản phẩm nào nhất trong nhóm mỹ phẩm dưới 200 nghìn?", bạn sẽ đứng hình. Dữ liệu đã bắn rồi, không quay lại được. Payload thiếu = phân tích chết.
Bài này tập trung 100% vào payload — tức là bộ properties (thuộc tính) đi kèm mỗi event. Chúng ta sẽ xem các ví dụ payload chuẩn cho từng loại sản phẩm, học các best practice về kiểu dữ liệu, cách đặt tên property, và những cạm bẫy khiến payload trở nên vô giá trị. Đây là kỹ năng nền tảng: một PM viết payload tốt sẽ tiết kiệm cho team hàng chục giờ query và tránh việc phải "làm lại tracking" — thứ đắt đỏ và đau đớn nhất trong analytics.
Khái niệm cốt lõi
Event, property và payload là gì
Một event gửi lên công cụ analytics gồm ba phần chính:
- Tên event (event name): động từ mô tả hành động, ví dụ
product_viewed,checkout_started. - Event properties: các thuộc tính mô tả ngữ cảnh của chính hành động đó — ví dụ
product_id,price,payment_method. Đây là phần thay đổi theo từng lần bắn. - User properties (people properties): thuộc tính mô tả con người thực hiện, ví dụ
plan,city,signup_date. Phần này sẽ được đào sâu ở Bài 12, nên ở bài này ta chỉ chạm qua ở mức phân biệt.
product_viewed tối thiểu trông như sau:{
"event": "product_viewed",
"user_id": "user_123",
"timestamp": "2026-05-11T10:23:00Z",
"properties": {
"product_id": "SKU_88213",
"product_name": "Serum Vitamin C 30ml",
"category": "skincare",
"brand": "Cocoon",
"price": 189000,
"currency": "VND",
"in_stock": true,
"source": "search_results",
"position": 3
}
}
Chỉ với payload này, bạn đã trả lời được: sản phẩm nào được xem, thuộc nhóm nào, giá bao nhiêu, khách đến từ đâu (kết quả tìm kiếm), và ở vị trí thứ mấy trong danh sách. Mỗi property là một "chiều" (dimension) để bạn cắt lát dữ liệu về sau.
Bốn nguyên tắc vàng của một property tốt
1. Kiểu dữ liệu nhất quán (consistent types). Một property phải luôn giữ cùng một kiểu. Nếu price lúc là số 189000, lúc là chuỗi "189.000đ", lúc là "free", thì Mixpanel/Amplitude sẽ coi đó là hai property khác nhau và bạn không thể tính tổng, tính trung bình. Số phải là số, boolean phải là true/false, ngày phải theo ISO 8601.
2. Đặt tên theo convention thống nhất. Chọn snake_case hoặc camelCase rồi giữ nguyên cho toàn hệ thống. Không được productId chỗ này, product_id chỗ kia. Property nên là danh từ mô tả thuộc tính, không phải câu.
3. Giá trị phải có độ phân giải (granularity) hợp lý — nhưng đừng nổ tung cardinality. category = "skincare" là tốt. Nhưng nếu bạn đưa nguyên search_query do người dùng tự gõ vào làm property có cardinality cao (hàng triệu giá trị khác nhau), bảng phân tích sẽ chậm và khó dùng. Với dữ liệu tự do như query, hãy cân nhắc lưu riêng.
4. Chuẩn hoá đơn vị. Tiền luôn kèm currency. Thời lượng luôn thống nhất đơn vị (giây hay mili-giây — chọn một). Boolean thay vì chuỗi "yes"/"no".
Semantic properties — chuẩn hoá theo ngành
Nhiều event lặp lại một bộ property giống nhau. Ví dụ mọi event liên quan mua hàng đều nên có: product_id, price, currency, quantity. Việc định nghĩa sẵn các bộ property chuẩn (gọi là semantic events trong Amplitude, hay tracking spec nói chung) giúp team không mỗi người bắn một kiểu. GA4 gọi đây là "recommended events" với parameter cố định như items, value, currency.
Tình huống thực tế
Ví dụ 1 — Tiki và event order_completed thiếu currency
Một team growth tại một sàn TMĐT lớn ở Việt Nam (mô phỏng theo tình huống Tiki thường gặp) triển khai Amplitude. Họ bắn event order_completed với payload gọn:
{
"event": "order_completed",
"properties": {
"order_id": "OD_772134",
"total": 450000,
"items_count": 3,
"payment_method": "momo"
}
}
Trong sáu tháng đầu mọi thứ ổn vì họ chỉ bán ở Việt Nam. Nhưng khi mở rộng bán hàng xuyên biên giới, họ thêm giao dịch tính bằng USD. Vì payload không có currency, mọi total bị cộng dồn thành một con số vô nghĩa — 450.000 VND và 450 USD nằm chung một cột. Doanh thu báo cáo lên board sai lệch nghiêm trọng trong một tháng trước khi bị phát hiện.
Bài học: Với bất kỳ property tiền tệ nào, currency là bắt buộc từ ngày đầu, dù bạn "chắc chắn" chỉ có một đơn vị. Ngoài ra nên tách revenue (giá trị tính cho ARPU/LTV, xem Bài 19) và total (số khách trả thực tế) rõ ràng.
Ví dụ 2 — Một startup fintech và event screen_viewed cardinality nổ
Một startup ví điện tử tại TP.HCM muốn theo dõi màn hình người dùng xem. Họ bắn một event duy nhất screen_viewed với property screen_name. Ý tưởng đúng. Nhưng lập trình viên lỡ đưa cả tham số động vào tên màn hình:
{ "event": "screen_viewed", "properties": { "screen_name": "transaction_detail_OD_772134" } }
Mỗi giao dịch tạo ra một screen_name khác nhau. Sau ba tuần, property screen_name có hơn 400.000 giá trị unique. Dashboard "top screens" trở nên vô dụng, và Mixpanel bắt đầu cảnh báo cardinality cao. Giải pháp: tách thành screen_name = "transaction_detail" (giá trị cố định, cardinality thấp) và transaction_id = "OD_772134" (property riêng, dùng khi cần drill-down).
Bài học: Định danh động (ID, query, tên tự do) không bao giờ được nhét vào property phân loại có cardinality thấp. Tách ID ra property riêng.
Ví dụ 3 — MoMo và bộ property chuẩn hoá cho feature_used
Một team tại một siêu ứng dụng thanh toán (mô phỏng theo MoMo) có hàng chục tính năng: nạp tiền điện thoại, thanh toán hoá đơn, mua vé xem phim, ví trả sau. Ban đầu mỗi team con bắn event riêng: topup_done, bill_paid, movie_ticket_bought... Kết quả là không ai so sánh được mức độ dùng giữa các tính năng.
Họ chuẩn hoá lại thành một event feature_used với payload thống nhất:
{
"event": "feature_used",
"properties": {
"feature_name": "bill_payment",
"feature_category": "payments",
"transaction_value": 320000,
"currency": "VND",
"is_first_time": false,
"entry_point": "home_shortcut"
}
}
Giờ đây một câu query duy nhất trả lời được: tính năng nào có nhiều người dùng lần đầu (is_first_time = true), tính năng nào mang lại giá trị giao dịch cao, người dùng vào tính năng từ đâu (entry_point). Property is_first_time giúp họ phân tích activation (Bài 16) cực nhanh mà không cần join phức tạp.
Bài học: Khi có nhiều hành động tương tự, một event tổng quát với property phân loại (feature_name, feature_category) mạnh hơn nhiều event riêng lẻ. Property boolean như is_first_time cài sẵn giúp phân tích về sau đơn giản hoá đáng kể.
Hướng dẫn từng bước
Đây là quy trình thiết kế payload cho một event mới, áp dụng được cho mọi sản phẩm:
Bước 1 — Xác định câu hỏi phân tích trước khi viết property. Hỏi ngược: "Sáu tháng nữa tôi sẽ muốn cắt event này theo chiều nào?" Với checkout_started, có thể là: theo phương thức thanh toán, theo giá trị giỏ, theo có dùng mã giảm giá hay không, theo thiết bị. Mỗi câu hỏi là một property.
Bước 2 — Liệt kê property và gán kiểu dữ liệu rõ ràng. Viết ra dạng bảng: tên property, kiểu (string / number / boolean / datetime), ví dụ giá trị, bắt buộc hay tuỳ chọn.
{
"event": "checkout_started",
"properties": {
"cart_id": "CART_9981",
"cart_value": 780000,
"currency": "VND",
"items_count": 4,
"coupon_applied": true,
"coupon_code": "SALE20",
"payment_method": "vnpay",
"device_type": "mobile"
}
}
Bước 3 — Áp convention đặt tên. Kiểm tra toàn bộ property theo snake_case, danh từ, không viết tắt khó hiểu. dt nên là device_type.
Bước 4 — Chuẩn hoá đơn vị và enum. Xác định payment_method chỉ nhận một tập giá trị cố định: momo, vnpay, zalopay, cod, card. Ghi rõ tập enum này vào tài liệu để dev không tự bịa MoMo, Momo, momo_wallet.
Bước 5 — Phân biệt event property và user property. cart_value là event property (đổi mỗi lần). plan hay total_lifetime_orders là user property. Đừng nhét thuộc tính người dùng vào từng event nếu nó thuộc về hồ sơ người dùng.
Bước 6 — Ghi vào tracking plan và validate. Đưa payload chuẩn vào tracking plan chung (Bài 30 sẽ triển khai sâu). Trước khi lên production, bắn thử và kiểm tra trong Live View của Mixpanel/Amplitude xem đúng kiểu dữ liệu chưa. Bài 27 sẽ nói về validate tự động.
Lỗi thường gặp & mẹo
- Trộn kiểu dữ liệu. Lỗi phổ biến nhất.
price: "189000"(chuỗi) vàprice: 189000(số) là hai property khác nhau trong hệ thống. Luôn gửi số dạng number, đừng bọc trong dấu nháy. - Đưa ID hoặc text tự do vào property phân loại. Gây nổ cardinality như ví dụ fintech ở trên. ID để riêng, phân loại để riêng.
- Quên
currencycho property tiền. Dù chỉ bán trong nước cũng thêm — chi phí gần như bằng 0, nhưng cứu bạn khi mở rộng. - Property "câu văn" thay vì thuộc tính.
"user_clicked_the_red_buy_button": truelà sai. Nên là eventbutton_clickedvới propertybutton_id: "buy",button_color: "red". - Payload phình to vô ích. Đừng nhét 40 property "phòng khi cần". Mỗi property phải trả lời một câu hỏi phân tích thực. Payload gọn nhưng đủ chiều tốt hơn payload khổng lồ mà 90% không ai query.
- Timestamp không chuẩn. Luôn dùng ISO 8601 kèm timezone (
2026-05-11T10:23:00Z). Tránh gửi epoch tuỳ tiện lẫn lộn giây/mili-giây. - Mẹo
nullvs thiếu property. Nếu một property không áp dụng cho lần bắn này, tốt hơn là không gửi nó thay vì gửinullhay chuỗi rỗng, để tránh làm bẩn phân phối giá trị. - Mẹo boolean thay vì chuỗi.
is_first_purchase: truemạnh hơnfirst_purchase: "yes"— vừa dễ filter, vừa nhất quán.
Bài tập thực hành
- Thiết kế payload từ đầu. Chọn một sản phẩm bạn quen (ví dụ app giao đồ ăn). Thiết kế payload đầy đủ cho ba event:
restaurant_viewed,add_to_cart,order_completed. Với mỗi property, ghi rõ kiểu dữ liệu và một câu hỏi phân tích mà nó phục vụ.
- Bắt lỗi payload. Cho payload sau, hãy tìm ít nhất 4 lỗi và sửa lại:
{
"event": "User Bought Something",
"properties": {
"price": "1.200.000 VND",
"productID": "SKU_1",
"search_query": "son môi màu đỏ giá rẻ freeship",
"firstBuy": "yes"
}
}
- Chuẩn hoá đa tính năng. Bạn có ba event rời rạc
wallet_topup,bill_pay,buy_data_package. Hãy gộp thành một eventfeature_usedvới bộ property thống nhất, và chỉ rõ property nào là enum cố định.
Tóm tắt
Payload là "linh hồn" của mỗi event — tên event cho biết chuyện gì xảy ra, còn properties cho biết bối cảnh, cho phép bạn cắt lát và phân tích về sau. Bốn nguyên tắc vàng: kiểu dữ liệu nhất quán, đặt tên theo convention, cardinality hợp lý (tách ID/text tự do ra riêng), và chuẩn hoá đơn vị (đặc biệt là currency). Hãy luôn thiết kế property xuất phát từ câu hỏi phân tích, chuẩn hoá enum, phân biệt event property với user property, và validate trước khi lên production. Một payload tốt hôm nay giúp bạn tránh việc "làm lại tracking" đau đớn ngày mai — và đó là dấu hiệu của một PM thực sự dùng dữ liệu.