Documentation Index Fetch the complete documentation index at: https://docs.li2.ai/llms.txt
Use this file to discover all available pages before exploring further.
Hướng Dẫn Track Events
Trong hướng dẫn này : Bạn sẽ học cách sử dụng Li2 Analytics SDK để track lead events (signup, form submissions) và sale events (purchases, subscriptions) với các ví dụ thực tế.
Yêu Cầu
Trước khi track events, đảm bảo bạn đã:
Cài Đặt SDK Đã hoàn thành Setup Guide và cài đặt Li2 Analytics SDK
Enable Tracking Đã bật conversion tracking cho touchpoint trong Settings
Lead Tracking
Lead event đánh dấu khi khách hàng thể hiện sự quan tâm đến sản phẩm/dịch vụ của bạn. Đây là bước trung gian quan trọng giữa visit và sale.
Khi Nào Track Lead?
Khi khách hàng điền form liên hệ, đăng ký nhận tư vấn, hoặc request demo. Ví dụ : Form “Liên hệ chúng tôi”, “Đặt lịch demo”, “Nhận báo giá”
Khi khách hàng tạo tài khoản mới hoặc đăng ký trial. Ví dụ : Đăng ký Free plan, Start trial, Tạo account
Khi khách hàng subscribe newsletter hoặc email updates. Ví dụ : Đăng ký nhận tin tức, Subscribe blog updates
Khi khách hàng thực hiện hành động có ý định cao. Ví dụ : Add to cart, Download whitepaper, Xem pricing page
Cách Track Lead
Client-Side (Browser)
Server-Side (Node.js)
Sử dụng khi : Track trực tiếp trong browser sau khi user submit form hoặc signup.// Sau khi user submit form thành công
li2Analytics . trackLead ({
eventName: "Contact Form Submitted" ,
customerExternalId: "user_12345" , // Your internal user ID
customerEmail: "[email protected] " ,
customerName: "Nguyễn Văn A" ,
metadata: {
formType: "contact" ,
message: "Interested in premium plan" ,
source: "landing_page"
}
})
. then ( result => {
if ( result . success ) {
console . log ( 'Lead tracked!' , result . customerId );
} else {
console . error ( 'Failed:' , result . message );
}
});
Click ID tự động : SDK tự động lấy click ID từ cookie li_cid, bạn không cần truyền thủ công.
Sử dụng khi : Track từ server sau webhook hoặc async processing.import { initServer } from '@li2/analytics' ;
const li2 = initServer ({
apiKey: process . env . LI2_SECRET_KEY // li2_sk_...
});
// Track lead từ server
const result = await li2 . trackLead ({
clickId: "cm3w..." , // REQUIRED - lấy từ client
eventName: "Trial Signup" ,
customerExternalId: "user_12345" ,
customerEmail: "[email protected] " ,
customerName: "Nguyễn Văn A" ,
metadata: {
plan: "pro_trial" ,
referrer: "google_ads"
}
});
if ( result . success ) {
console . log ( 'Lead tracked:' , result . customerId );
}
Click ID Required : Server không thể auto-detect click ID. Bạn phải capture click ID từ client và gửi lên server.// Client-side: capture click ID
const clickId = li2Analytics . getClickId ();
// Gửi lên server cùng form data
fetch ( '/api/submit-form' , {
method: 'POST' ,
body: JSON . stringify ({ clickId , ... formData })
});
Lead Parameters
Parameter Type Required Description eventNamestring ✅ Tên lead event (VD: “Signup”, “Contact Form”) customerExternalIdstring ✅ ID khách hàng trong hệ thống của bạn customerEmailstring ⚪ Email khách hàng (khuyến nghị) customerNamestring ⚪ Tên khách hàng customerAvatarstring ⚪ URL avatar metadataobject ⚪ Dữ liệu bổ sung (max 10,000 chars) clickIdstring Server only Click ID (chỉ cần khi track từ server)
Best Practice cho customerExternalId : Sử dụng ID persistent và unique:
✅ User ID từ database: "user_12345"
✅ Email nếu chưa có account: "[email protected] "
❌ Session ID (không persistent): "sess_abc123"
ID này dùng để link lead → sale events của cùng một khách hàng.
Sale Tracking
Sale event đánh dấu conversion thành công - khách hàng đã hoàn thành giao dịch mua hàng.
Khi Nào Track Sale?
Khi khách hàng hoàn thành thanh toán và order được confirm. Timing : Sau khi payment processor confirm success (webhook từ Stripe, PayPal, etc.)
Khi khách hàng subscribe plan trả phí (monthly/annual). Timing : Sau khi first payment thành công hoặc trial convert to paid
Khi khách hàng thanh toán dịch vụ (consulting, booking, etc.). Timing : Sau khi payment confirmed hoặc booking confirmed with payment
Cách Track Sale
Client-Side (Browser)
Server-Side (Webhook)
Sử dụng khi : Track ngay sau checkout success trên thank-you page.// Trên Thank You Page sau khi checkout thành công
li2Analytics . trackSale ({
customerExternalId: "user_12345" ,
amount: 4999 , // $49.99 in cents
eventName: "Product Purchase" ,
currency: "usd" ,
invoiceId: "inv_abc123" , // Unique invoice ID
paymentProcessor: "stripe" ,
customerEmail: "[email protected] " ,
customerName: "Nguyễn Văn A" ,
metadata: {
productId: "prod_premium" ,
productName: "Premium Plan - Annual" ,
discount: "SAVE20"
}
})
. then ( result => {
if ( result . success ) {
console . log ( 'Sale tracked!' , result . saleEventId );
}
});
Amount Format : LUÔN sử dụng smallest currency unit (cents, xu, etc.)
✅ 4999 (nghĩa là $49.99)
❌ 49.99 (sẽ được hiểu là $0.4999)
Sử dụng khi : Track từ payment webhook để đảm bảo accuracy.// Next.js API Route - Stripe Webhook Handler
import { initServer } from '@li2/analytics' ;
import Stripe from 'stripe' ;
const stripe = new Stripe ( process . env . STRIPE_SECRET_KEY );
const li2 = initServer ({ apiKey: process . env . LI2_SECRET_KEY });
export async function POST ( request ) {
const sig = request . headers . get ( 'stripe-signature' );
const event = stripe . webhooks . constructEvent (
await request . text (),
sig ,
process . env . STRIPE_WEBHOOK_SECRET
);
if ( event . type === 'checkout.session.completed' ) {
const session = event . data . object ;
// Lấy click ID từ session metadata (đã lưu khi tạo checkout)
const clickId = session . metadata . clickId ;
await li2 . trackSale ({
clickId: clickId , // REQUIRED for server-side
customerExternalId: session . customer ,
amount: session . amount_total ,
currency: session . currency ,
invoiceId: session . payment_intent ,
paymentProcessor: "stripe" ,
eventName: "Subscription Purchase" ,
metadata: {
planId: session . metadata . planId ,
interval: session . metadata . interval
}
});
}
return Response . json ({ received: true });
}
Lưu Click ID vào Payment Session :// Client: khi tạo Stripe checkout session
const clickId = li2Analytics . getClickId ();
fetch ( '/api/create-checkout' , {
method: 'POST' ,
body: JSON . stringify ({
clickId , // Gửi lên server
planId: 'premium'
})
});
// Server: lưu vào Stripe session metadata
const session = await stripe . checkout . sessions . create ({
metadata: {
clickId: clickId , // Lưu để dùng trong webhook
planId: planId
},
// ...other params
});
Sale Parameters
Parameter Type Required Description customerExternalIdstring ✅ ID khách hàng (phải giống với lead event) amountnumber ✅ Số tiền (smallest unit: cents, xu) eventNamestring ⚪ Tên sale event (default: “Purchase”) currencystring ⚪ Mã tiền tệ (default: “usd”) invoiceIdstring ⚪ Invoice/transaction ID (dùng để dedupe) paymentProcessorstring ⚪ Payment processor (“stripe”, “paypal”, etc.) customerEmailstring ⚪ Email (auto-create customer nếu chưa có) customerNamestring ⚪ Tên khách hàng metadataobject ⚪ Dữ liệu bổ sung (max 10,000 chars) clickIdstring Server only Click ID (chỉ cần khi track từ server)
Multi-currency Support : Li2 hiện hỗ trợ tracking revenue trong 2 loại tiền tệ:
USD (US Dollar): currency: "usd"
VND (Vietnamese Dong): currency: "vnd"
Li2 tự động convert sang default currency của organization để tính tổng revenue
Original currency được lưu giữ trong event data
Common Use Cases
SaaS Signup → Subscription
E-commerce: Product Purchase
Lead Gen: Form → Consultation Booking
Funnel: Visit → Trial Signup → Paid Subscription Step 1: User clicks touchpoint link Li2 tự động capture click ID và lưu vào cookie
Step 2: User signs up for trial (Lead Event) // Sau khi signup form submit thành công
li2Analytics . trackLead ({
eventName: "Trial Signup" ,
customerExternalId: newUser . id ,
customerEmail: newUser . email ,
customerName: newUser . name ,
metadata: {
plan: "pro_trial" ,
trialDays: 14
}
});
Step 3: User subscribes after trial (Sale Event) // Trong Stripe webhook handler
await li2 . trackSale ({
clickId: savedClickId , // Đã lưu khi signup
customerExternalId: user . id ,
amount: 2900 , // $29/month
currency: "usd" ,
eventName: "Subscription Started" ,
paymentProcessor: "stripe" ,
invoiceId: invoice . id ,
metadata: {
plan: "pro_monthly" ,
billingInterval: "month"
}
});
Funnel: Visit → Add to Cart → Checkout → Purchase Step 1: User adds to cart (Optional Lead) // Track add-to-cart như high-intent lead
li2Analytics . trackLead ({
eventName: "Add to Cart" ,
customerExternalId: user . id || user . email ,
customerEmail: user . email ,
metadata: {
productId: product . id ,
productName: product . name ,
cartValue: product . price
}
});
Step 2: User completes purchase (Sale Event) // Trên order confirmation page
li2Analytics . trackSale ({
customerExternalId: order . customerId ,
amount: order . total , // Already in cents
currency: "vnd" ,
eventName: "Order Completed" ,
invoiceId: order . id ,
paymentProcessor: "momo" ,
customerEmail: order . email ,
metadata: {
items: order . items . map ( i => ({
id: i . id ,
name: i . name ,
quantity: i . quantity
})),
shippingMethod: order . shippingMethod
}
});
Step 1: User submits contact form (Lead Event) li2Analytics . trackLead ({
eventName: "Contact Form Submitted" ,
customerExternalId: formData . email , // Dùng email nếu chưa có user ID
customerEmail: formData . email ,
customerName: formData . name ,
metadata: {
message: formData . message ,
interestedService: formData . service ,
preferredContactMethod: formData . contactMethod
}
});
Step 2: User books paid consultation (Sale Event) // Sau khi booking & payment thành công
li2Analytics . trackSale ({
customerExternalId: customer . email , // Phải giống lead event
amount: 15000000 , // 15,000,000 VND = 15000000 (không có decimal)
currency: "vnd" ,
eventName: "Consultation Booked" ,
invoiceId: booking . id ,
paymentProcessor: "vnpay" ,
metadata: {
consultationType: "premium" ,
duration: "60_minutes" ,
scheduledDate: booking . date
}
});
VND Currency : VND không có subunit (không có xu), nên amount là số nguyên:
✅ 15000000 = 15 triệu VND
❌ 15000000.00 không cần .00
Best Practices
1. Consistent customerExternalId Across Events
QUAN TRỌNG : Sử dụng CÙNG MỘT customerExternalId cho cả lead và sale events của cùng khách hàng.// ✅ ĐÚNG: Cùng ID
trackLead ({ customerExternalId: "user_123" , ... })
trackSale ({ customerExternalId: "user_123" , ... })
// ❌ SAI: Khác ID
trackLead ({ customerExternalId: "user_123" , ... })
trackSale ({ customerExternalId: "order_456" , ... }) // Li2 không link được
Tại sao : Li2 dùng customerExternalId để link lead → sale và aggregate metrics.
2. Track Sale Từ Server-Side (Recommended)
Lý do nên track sale từ server :
✅ Chống fraud: User không thể fake sale event
✅ Accuracy: Webhook confirms payment thực sự thành công
✅ Reliability: Không bị ảnh hưởng bởi ad blockers hoặc network issues
Timing : Track trong payment webhook handler (Stripe, PayPal, etc.)
3. Sử dụng invoiceId Để Handle Webhook Retries
Khi webhook được retry (Stripe, PayPal thường retry khi timeout), invoiceId giúp Li2 tránh duplicate trong vòng 7 ngày : trackSale ({
invoiceId: "inv_abc123" , // Unique per transaction
amount: 4999 ,
// ...
});
Cách hoạt động :
Trong 7 ngày : Li2 cache và trả về response cũ, không tạo duplicate
Sau 7 ngày : Cache expire, có thể tạo sale event mới nếu gửi lại
Use case : Đủ để handle webhook retries phổ biến (Stripe retry trong 72h). Không phải permanent deduplication.
4. Metadata Cho Reporting & Analysis
5. Handle Errors Gracefully
Tracking failures không nên block user experience: try {
const result = await li2Analytics . trackSale ({ ... });
if ( ! result . success ) {
// Log error nhưng KHÔNG show lỗi cho user
console . error ( 'Tracking failed:' , result . message );
// Optionally: retry hoặc log to error tracking service
}
} catch ( error ) {
console . error ( 'Tracking error:' , error );
// User vẫn thấy success message của purchase
}
Utility Functions
Li2 Analytics SDK cung cấp các helper functions:
isTrackingAvailable()
Kiểm tra xem click ID có available hay không (user có đến từ tracked link không):
if ( li2Analytics . isTrackingAvailable ()) {
// User came from a Li2 touchpoint
trackLead ({ ... });
} else {
// User came from direct traffic or other sources
// Skip tracking hoặc handle differently
}
getClickId()
Lấy click ID hiện tại (useful khi cần gửi lên server):
const clickId = li2Analytics . getClickId ();
if ( clickId ) {
// Gửi lên server để track sau
await fetch ( '/api/save-lead' , {
method: 'POST' ,
body: JSON . stringify ({ clickId , ... formData })
});
}
Troubleshooting
Lead/Sale không xuất hiện trong dashboard?
Check list :
Verify response : Check console hoặc Network tab
const result = await trackLead ({ ... });
console . log ( result ); // { success: true/false, message: ... }
Click ID available?
console . log ( 'Click ID:' , li2Analytics . getClickId ());
// Nếu null → user không đến từ tracked link
Touchpoint có enable conversion tracking?
Vào touchpoint Settings → Conversion Tracking phải ON
Allowed hostnames configured?
Settings → Analytics → Allowed Hostnames phải có domain hiện tại
Publishable key đúng?
Verify key trong script tag khớp với Settings → Analytics
Error: 'customerExternalId is required'
// ❌ Missing customerExternalId
trackLead ({
eventName: "Signup"
// customerExternalId: ... <- THIẾU
});
// ✅ Fixed
trackLead ({
eventName: "Signup" ,
customerExternalId: user . id // REQUIRED
});
Sale không link được với Lead?
Nguyên nhân phổ biến : customerExternalId không match.// Lead event
trackLead ({ customerExternalId: "user_123" , ... })
// Sale event - PHẢI DÙNG CÙNG ID
trackSale ({ customerExternalId: "user_123" , ... }) // ✅
trackSale ({ customerExternalId: "order_456" , ... }) // ❌
Verify : Check customer profile trong dashboard xem có cả lead và sale events không.
Check amount format : Phải dùng smallest currency unit // ❌ SAI
trackSale ({ amount: 49.99 , currency: "usd" }) // → $0.49 (!!)
// ✅ ĐÚNG
trackSale ({ amount: 4999 , currency: "usd" }) // → $49.99
VND Example :// ✅ ĐÚNG
trackSale ({ amount: 500000 , currency: "vnd" }) // → 500,000 VND
Server-side tracking: 'clickId is required'
Server không thể auto-detect click ID. Bạn PHẢI capture từ client: // ❌ SAI: Server-side tracking without clickId
li2 . trackLead ({
eventName: "Signup" ,
customerExternalId: "user_123"
// clickId: ... <- THIẾU
});
// ✅ ĐÚNG: Capture từ client, gửi lên server
// Client:
const clickId = li2Analytics . getClickId ();
fetch ( '/api/signup' , {
body: JSON . stringify ({ clickId , ... data })
});
// Server:
li2 . trackLead ({
clickId: clickId , // From client
eventName: "Signup" ,
customerExternalId: "user_123"
});
Next Steps
GTM Integration Triển khai tracking qua Google Tag Manager
Configure Goals Thiết lập conversion goals và target KPIs