1. Vì sao cần đo lường workflow
Nói ngắn gọn: không có phân tích, bạn sống trong chế độ “tôi đoán vậy”, chứ không phải “tôi biết chắc”.
Trong các bài trước của mô‑đun này, chúng ta đã chẻ nhỏ kịch bản thành các bước, phân vai cho GPT, widget và MCP, bàn về tool‑gating và lưu trạng thái giữa các bước. Giờ hãy nhìn cùng cấu trúc đó dưới góc độ phân tích: liệu mọi thứ có hoạt động như dự định, và người dùng thật sự bị kẹt ở đâu.
Trong web truyền thống, mọi người đã quen với phễu: có bao nhiêu người đến landing, bao nhiêu người cho sản phẩm vào giỏ, bao nhiêu người đi đến thanh toán. Trong ChatGPT App cũng tương tự, chỉ khác là thay vì trang, bạn có các bước của workflow, và thay vì “nhấp nút Mua” — là tổ hợp phát ngôn của người dùng, lời gọi công cụ và tương tác với widget.
Khi bạn xây dựng một kịch bản phức tạp mà không có chỉ số, bạn sẽ không thấy:
- người dùng thường “rời bỏ” ở bước nào;
- họ bị treo và đọc mất cả phút ở đâu (hoặc chỉ là đi pha trà rồi không quay lại);
- bước nào hoàn toàn không mang lại giá trị mà chỉ gây khó chịu;
- cách thay đổi trong prompt hoặc tool gating ảnh hưởng đến hành vi.
Mục tiêu của phân tích theo bước rất đơn giản: học cách tăng tỷ lệ kịch bản được hoàn thành, rút ngắn thời gian đến kết quả và giảm số lỗi cũng như số lượt liên hệ hỗ trợ.
Từ thời điểm này, workflow không chỉ là một đối tượng kiến trúc hay một UX‑quest. Nó còn là một thứ có thể đo đếm bằng con số.
2. Phễu kịch bản trong ChatGPT App
Trong web cổ điển, phễu trông tuyến tính: Landing → Product → Cart → Checkout. Trong ChatGPT App, bức tranh thú vị hơn một chút: người dùng có thể “nhảy cóc” bước bằng lời nói, mô hình đôi khi có thể bỏ qua bước, còn widget và văn bản hội thoại có thể bị mất đồng bộ.
Tuy vậy, ý tưởng cơ bản vẫn thế: chúng ta có một chuỗi bước, và ở mỗi bước một phần người dùng đi tiếp, một phần thì không.
Lấy ví dụ GiftGenius của chúng ta:
- collect_recipient — ChatGPT và widget thu thập dữ liệu cơ bản về người nhận (giới tính, tuổi, quan hệ, sở thích).
- collect_budget — làm rõ ngân sách và đơn vị tiền tệ.
- suggest_ideas — MCP/agent gợi ý ý tưởng và trả về thẻ quà trong widget.
- review_selection — người dùng thích/ẩn ý tưởng và chọn 1–2 mục ưa thích.
- checkout — tạo commerce intent, tiến hành đặt hàng.
Ở dạng phễu có thể vẽ như sau:
flowchart TD
A[Bắt đầu workflow] --> B["1\. Người nhận"]
B --> C["2\. Ngân sách"]
C --> D["3\. Ý tưởng quà tặng"]
D --> E["4\. Chọn quà"]
E --> F["5\. Checkout"]
Nhưng cần nhớ: người dùng có thể viết trong chat “Chuyển thẳng sang thanh toán” hoặc “Hiển thị trước các lựa chọn đắt tiền”, và mô hình có thể quyết định nhảy qua một số bước. Vì vậy, phân tích theo bước trong ChatGPT App không chỉ là các màn hình UI mà còn là hành vi của mô hình: những bước nào thực sự diễn ra, theo thứ tự nào, và ai khởi tạo chuyển bước — người dùng, widget hay GPT.
3. Các chỉ số cơ bản theo bước
Bắt đầu từ các kinh điển của phân tích sản phẩm và điều chỉnh một chút cho ChatGPT App.
Đối với mỗi workflow, chúng ta cần tối thiểu bốn chỉ số cơ bản.
Để tiện, hãy gom chúng vào bảng:
| Chỉ số | Ý nghĩa | Câu hỏi điển hình |
|---|---|---|
| Start rate | Bao nhiêu người dùng thực sự bắt đầu kịch bản | App của chúng ta có được hiển thị cho ai không? |
| Completion rate | Bao nhiêu người dùng đi đến cuối cùng | Kịch bản có đưa tới kết quả tốt đến mức nào? |
| Conversion per step | Tỷ lệ người dùng chuyển từ bước N sang bước N+1 | Chính xác bước nào của chúng ta đang “rò rỉ”? |
| Drop-off per step | Tỷ lệ người dùng rời bỏ ở bước N | Ở bước nào người dùng bỏ cuộc nhiều nhất? |
Gần như luôn bổ sung các chỉ số về nỗ lực:
- thời gian trung bình ở bước (nơi người dùng “bị treo”);
- số tương tác ở bước (cần bao nhiêu tin nhắn/nhấp chuột);
- tỷ lệ bước kết thúc bằng lỗi hoặc cần thử lại.
Trong bối cảnh kịch bản LLM, còn có những thứ đặc thù hơn, như độ chính xác khi mô hình chọn công cụ hoặc tỷ lệ câu trả lời “ảo tưởng” ở một bước cụ thể, nhưng đó là phần nâng cao — chúng ta sẽ quay lại ở các mô‑đun cuối.
Đối với kịch bản thương mại (commerce), phía trên các bước sẽ có thêm các chỉ số kinh doanh:
- chuyển đổi sang thanh toán tính từ lúc bắt đầu workflow;
- chuyển đổi sang thanh toán tính từ một bước cụ thể (ví dụ, từ “gợi ý ý tưởng”);
- giá trị đơn hàng trung bình;
- tỷ lệ hủy/hoàn trả.
Quan trọng: các con số này không tồn tại độc lập, giữa chúng có quan hệ nhân‑quả. Một bước có drop‑off cao không phải lúc nào cũng tệ: có thể nó đang lọc người dùng không phù hợp và về sau chỉ còn lại những ai thực sự thấy kịch bản hữu ích. Vì thế, phân tích không chỉ là “đếm phần trăm”, mà là biết kể câu chuyện từ dữ liệu.
Để có thể tính được các phần trăm và phễu nói trên, chúng ta cần các sự kiện thô: ai, khi nào và đã đi qua (hoặc không đi qua) bước nào. Phần tiếp theo sẽ thống nhất về định dạng các sự kiện như vậy.
4. Sự kiện phân tích trông như thế nào
Trước khi viết mã, cần thống nhất định dạng “sự kiện” (event) mà chúng ta sẽ gửi từ widget và backend.
Thông thường một sự kiện phân tích bao gồm:
- ai: định danh người dùng hoặc ít nhất là phiên;
- workflow nào và phiên bản nào;
- bước nào;
- điều gì đã xảy ra (loại sự kiện);
- có thành công hay không, mất bao lâu;
- một ít metadata (locale, thiết bị, v.v.).
Có thể mô tả lược đồ sự kiện đơn giản cho workflow như sau:
export type WorkflowEventType =
| "workflow_started"
| "workflow_finished"
| "step_started"
| "step_completed"
| "step_failed";
export interface WorkflowAnalyticsEvent {
eventId: string; // uuid
timestamp: string; // chuỗi ISO
userId?: string; // nếu có thể giải ẩn danh
conversationId?: string; // id cuộc hội thoại ChatGPT (nếu có)
workflowId: string; // định danh nội bộ của chúng ta
workflowType: "gift_selection";
workflowVersion: string; // ví dụ, "1.2.0" hoặc "1.2.0-A"
stepName?: string; // collect_budget, suggest_ideas, v.v.
eventType: WorkflowEventType;
toolName?: string; // nếu liên quan đến tool-call
success?: boolean;
errorCode?: string | null;
durationMs?: number;
metadata?: Record<string, unknown>;
}
Một vài lưu ý:
Thứ nhất, workflowVersion rất quan trọng nếu bạn định làm A/B test: không có nó, bạn sẽ không bao giờ biết biến thể nào của kịch bản cho kết quả tốt hơn.
Thứ hai, conversationId hoặc một correlation ID khác cho phép liên kết các sự kiện: các bước trong widget, lời gọi tool trong MCP và văn bản hội thoại. Ở các mô‑đun sau chúng ta sẽ nói thêm về tracing và observability, nhưng thói quen nghĩ đến các định danh “xuyên suốt” ngay từ đầu là rất hữu ích.
Thứ ba, không cần nhồi hết mọi thứ vào sự kiện: văn bản đầy đủ của tin nhắn, e‑mail, địa chỉ và các PII khác nên được tránh hoặc ẩn danh nghiêm ngặt — về chủ đề này chúng ta sẽ nói kỹ hơn ở phần cuối.
5. Instrumentation trong widget (Next.js + Apps SDK)
Giờ đến phần thú vị nhất: làm sao để widget GiftGenius tự lặng lẽ báo cáo các bước khi người dùng đi qua kịch bản.
Giả sử ở các bài trước bạn đã có thứ gì đó như sau:
// components/GiftWizard.tsx
type StepId = "recipient" | "budget" | "ideas" | "review" | "checkout";
export function GiftWizard() {
const [currentStep, setCurrentStep] = useState<StepId>("recipient");
const [workflowId] = useState(() => crypto.randomUUID());
// ... vẽ các bước khác
}
Thêm một “lớp phân tích” nhỏ dưới dạng hook.
Hook useWorkflowAnalytics
Tạo một wrapper biết về workflowId, workflowVersion và có thể gửi sự kiện tới API route Next.js của chúng ta /api/workflow-analytics.
// lib/useWorkflowAnalytics.ts
import { useCallback } from "react";
import type { WorkflowAnalyticsEvent, WorkflowEventType } from "./types";
const WORKFLOW_VERSION = "1.0.0";
export function useWorkflowAnalytics(
workflowId: string,
workflowType: WorkflowAnalyticsEvent["workflowType"] = "gift_selection"
) {
const sendEvent = useCallback(
async (payload: Omit<WorkflowAnalyticsEvent, "eventId" | "timestamp" | "workflowType" | "workflowVersion" | "workflowId">) => {
const event: WorkflowAnalyticsEvent = {
eventId: crypto.randomUUID(),
timestamp: new Date().toISOString(),
workflowId,
workflowType,
workflowVersion: WORKFLOW_VERSION,
...payload,
};
// gửi đơn giản tới API; ở production có thể thêm buffer/debounce
await fetch("/api/workflow-analytics", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(event),
});
},
[workflowId, workflowType]
);
const trackStepEvent = useCallback(
async (stepName: string, eventType: WorkflowEventType, extra?: Partial<WorkflowAnalyticsEvent>) => {
await sendEvent({ stepName, eventType, ...extra });
},
[sendEvent]
);
return { sendEvent, trackStepEvent };
}
Điểm quan trọng là hook này không phụ thuộc vào UI cụ thể của bước. Nó chỉ biết stepName và eventType là gì. Các component cụ thể sẽ nói với nó: “tôi bắt đầu bước”, “tôi đã hoàn tất bước”, v.v.
Gửi workflow_started và workflow_finished
Trong component GiftWizard, ở thời điểm mount và unmount có thể đăng ký bắt đầu và kết thúc kịch bản:
// components/GiftWizard.tsx
export function GiftWizard() {
const [currentStep, setCurrentStep] = useState<StepId>("recipient");
const [workflowId] = useState(() => crypto.randomUUID());
const { sendEvent } = useWorkflowAnalytics(workflowId);
useEffect(() => {
void sendEvent({ eventType: "workflow_started" });
return () => {
void sendEvent({ eventType: "workflow_finished" });
};
}, [sendEvent]);
// ...
}
Tất nhiên, coi unmount là kết thúc chỉ là xấp xỉ thô: người dùng có thể chỉ thu nhỏ chat hoặc chuyển sang hội thoại khác. Nhưng ngay cả chỉ số thô như vậy đã cho thấy có bao nhiêu kịch bản “đi được đến đâu đó”.
Theo dõi sự kiện theo bước
Giờ hãy để mỗi bước tự báo cáo về analytics. Trước hết thêm một wrapper đơn giản:
interface StepProps {
stepId: StepId;
onNext: () => void;
trackStepEvent: (stepName: string, eventType: WorkflowEventType, extra?: Partial<WorkflowAnalyticsEvent>) => Promise<void>;
}
function StepRecipient({ stepId, onNext, trackStepEvent }: StepProps) {
useEffect(() => {
void trackStepEvent(stepId, "step_started");
}, [stepId, trackStepEvent]);
const handleSubmit = async () => {
// ... xác thực, lưu vào widgetState
await trackStepEvent(stepId, "step_completed");
onNext();
};
return (
<div>
{/* các trường form của người nhận */}
<button onClick={handleSubmit}>Tiếp tục</button>
</div>
);
}
Trong GiftWizard, truyền trackStepEvent:
export function GiftWizard() {
// ...
const { trackStepEvent } = useWorkflowAnalytics(workflowId);
const goToNext = () => {
setCurrentStep((prev) => NEXT_STEP[prev]);
};
if (currentStep === "recipient") {
return (
<StepRecipient
stepId="recipient"
onNext={goToNext}
trackStepEvent={trackStepEvent}
/>
);
}
// các bước còn lại...
}
Tương tự, ở những bước có khả năng lỗi (ví dụ, gọi API bên ngoài trong suggest_ideas), khi thất bại có thể gửi "step_failed" kèm errorCode, còn khi tải phương án thành công — gửi "step_completed".
Nhờ vậy chúng ta có được:
- danh sách sự kiện rõ ràng: khi nào các bước bắt đầu và kết thúc;
- khả năng tính thời lượng bước: chênh lệch giữa "step_started" và "step_completed";
- tầm nhìn về những bước thường xuyên kết thúc bằng "step_failed".
6. Instrumentation trên backend / MCP
Analytics phía client là tốt, nhưng widget sống trong một thế giới khá mong manh: trình duyệt người dùng, iframe, sandbox và mọi hạn chế liên quan. Vì thế, song song cần ghi log sự kiện ở phía server — trong các công cụ MCP hoặc backend API của App.
Ví dụ, bạn có công cụ suggest_gifts thực hiện công việc nặng: truy vấn product feed, áp dụng bộ lọc và trả về quà tặng. Bên trong công cụ như vậy bạn có thể ghi log cả logic nghiệp vụ lẫn sự kiện phân tích.
Trình xử lý MCP‑tool giả định bằng TypeScript có thể như sau:
// mcp/tools/suggestGifts.ts
import type { SuggestGiftsArgs } from "../schemas";
import { logWorkflowEvent } from "../analytics/log";
export async function handleSuggestGifts(args: SuggestGiftsArgs, context: { workflowId: string; stepName: string }) {
const startedAt = Date.now();
try {
// ... logic chính để gợi ý ý tưởng
await logWorkflowEvent({
workflowId: context.workflowId,
workflowType: "gift_selection",
workflowVersion: "1.0.0",
stepName: context.stepName,
eventType: "step_completed",
toolName: "suggest_gifts",
success: true,
durationMs: Date.now() - startedAt,
});
return {
content: [{ type: "text", text: "Đã tìm thấy 5 ý tưởng quà tặng." }],
_meta: {
// dữ liệu thô cho widget
},
};
} catch (e) {
await logWorkflowEvent({
workflowId: context.workflowId,
workflowType: "gift_selection",
workflowVersion: "1.0.0",
stepName: context.stepName,
eventType: "step_failed",
toolName: "suggest_gifts",
success: false,
errorCode: "SUGGEST_FAILED",
durationMs: Date.now() - startedAt,
});
throw e;
}
}
Còn logWorkflowEvent có thể ghi vào cùng bảng/kho nơi lưu các sự kiện từ front, chỉ thêm nhãn "source": "backend".
Vì sao phân tích phía server đáng tin cậy hơn
Thứ nhất, một lời gọi tool hoặc xảy ra, hoặc không — đó là sự thật rõ ràng, không phải kiểu “có vẻ người dùng đã nhấp nút”.
Thứ hai, trên server dễ tổng hợp dữ liệu hơn: bạn có thể đếm mỗi công cụ được gọi bao nhiêu lần, durationMs trung bình là bao nhiêu, và tỷ lệ lỗi là bao nhiêu.
Thứ ba, nhờ vậy bạn thấy được khác biệt giữa vấn đề UX (người dùng không đến bước có lời gọi công cụ) và vấn đề kỹ thuật (đến bước rồi nhưng công cụ hay bị lỗi).
7. Cách đọc dữ liệu: tìm nút thắt cổ chai
Giả sử bạn đã hiện thực việc gửi các sự kiện "workflow_started", "step_started", "step_completed" và "step_failed" từ widget và MCP, và kho đã tích lũy đủ dữ liệu. Hãy tưởng tượng bạn đã thu thập một lượng dữ liệu nhất định cho GiftGenius và có thống kê tổng hợp theo bước. Bảng dưới đây đưa ra các con số giả định cho 1000 workflow đã khởi chạy:
| Bước | Bắt đầu bước | Hoàn tất bước | Drop‑off tại bước | Thời gian trung bình (giây) |
|---|---|---|---|---|
| recipient | 1000 | 950 | 5% | 12 |
| budget | 950 | 700 | 26% | 35 |
| ideas | 700 | 680 | 3% | 8 |
| review | 680 | 500 | 26% | 40 |
| checkout | 500 | 420 | 16% | 20 |
Nên chú ý điều gì ở đây:
Thứ nhất, bước budget — là nút thắt cổ chai rõ ràng. Drop‑off cao (26%) và thời gian trung bình cao hơn trông thấy. Có thể bạn hỏi quá nhiều về tiền tệ/thuế, câu chữ khó hiểu, hoặc người dùng đơn giản là chưa chắc chắn về ngân sách. Đây là ứng viên tốt để đơn giản hóa, tách thành hai tiểu bước hoặc thay đổi cách đặt câu hỏi.
Thứ hai, review cũng có tỷ lệ rơi rụng mạnh. Có thể UI thẻ quà tặng quá nặng, hoặc người dùng không hiểu “thích” một món quà nghĩa là gì. Cũng có thể mô hình trả về quá nhiều phương án, khiến widget giống danh sách vô tận. Lúc này nên nhìn không chỉ vào con số, mà cả screenshot/ghi hình phiên (nếu bạn có), hoặc ít nhất là tự đi qua kịch bản như một người dùng.
Thứ ba, checkout mất 16% — với kịch bản commerce là rất nhiều tiền. Nhưng cần hiểu mất ở đâu: ở khâu đặt hàng, ở lỗi của nhà cung cấp thanh toán, hay người dùng đổi ý. Đây không còn là câu hỏi UX thuần túy, mà là tổng hòa UX + ràng buộc kinh doanh.
Quan trọng là phân biệt được vấn đề UI và vấn đề mô hình.
- Nếu người dùng thường quay lại bước trước và đổi câu trả lời — đó là tín hiệu về câu hỏi không rõ ràng hay đặt kém.
- Nếu bước hoàn tất nhanh nhưng lời gọi tool ở đó hay thất bại — đó là vấn đề backend/MCP.
- Nếu bước kéo dài mà không có lỗi hay quay lại, có thể người dùng chỉ đang đọc một đoạn văn dài không quá cần thiết.
8. Thử nghiệm và A/B test cho workflow
Bản thân con số không cải thiện điều gì. Để phân tích có ích, bạn phải biết chạy thử nghiệm: thay đổi các bước và so sánh xem có tốt hơn không.
Trong bối cảnh ChatGPT App, thử nghiệm điển hình là so sánh hai phiên bản của một bước hoặc chuỗi bước:
- wizard dài với nhiều màn hình đơn giản so với một form phức tạp duy nhất;
- các cách diễn đạt câu hỏi khác nhau;
- thứ tự các bước khác nhau (ví dụ hỏi ngân sách sớm hay muộn);
- các chiến lược tool gating khác nhau (ít tool ở bước đầu, nhiều hơn ở bước sau).
Một thói quen tốt là cố định phiên bản kịch bản trong workflowVersion và thêm định danh thử nghiệm vào đó, ví dụ "1.3.0-A" và "1.3.0-B".
A/B split đơn giản trong widget
Dĩ nhiên, trong thực chiến bạn sẽ muốn phép gán ổn định ở mức người dùng hoặc phiên (qua backend), nhưng với ví dụ học tập thì chọn ngẫu nhiên là đủ.
// lib/useWorkflowVariant.ts
import { useMemo } from "react";
export type WorkflowVariant = "A" | "B";
export function useWorkflowVariant(): WorkflowVariant {
return useMemo(() => {
return Math.random() < 0.5 ? "A" : "B";
}, []);
}
Trong GiftWizard, xác định biến thể và truyền vào analytics:
export function GiftWizard() {
const [workflowId] = useState(() => crypto.randomUUID());
const variant = useWorkflowVariant();
const { sendEvent, trackStepEvent } = useWorkflowAnalytics(
workflowId,
"gift_selection"
);
useEffect(() => {
void sendEvent({
eventType: "workflow_started",
metadata: { variant },
});
}, [sendEvent, variant]);
// sau đó có thể thay đổi văn bản/cấu trúc bước tùy theo variant
}
Trên server có thể thay "1.0.0" cứng bằng cái gì đó như "1.1.0-A" và "1.1.0-B" hoặc chỉ log metadata.variant rồi nhóm theo trong analytics.
Ý nghĩa chính của A/B test: chọn trước chỉ số mục tiêu. Ví dụ: “chúng ta muốn tăng completion rate của kịch bản từ 42% lên 50%” hoặc “giảm thời gian ở bước budget đi 20%”. Không có chỉ số mục tiêu, mọi tái cấu trúc workflow sẽ giống như “đổi chỗ tủ, trông có vẻ đẹp hơn”.
9. Quyền riêng tư và đạo đức dữ liệu
Trước đây chúng ta đã lướt qua rằng trong metadata và sự kiện phân tích tốt hơn là không đưa PII một cách trực diện. Khi bàn về chỉ số, rất dễ bị cuốn và bắt đầu log mọi thứ. Nhưng hãy nhớ bạn đang làm việc bên trong ChatGPT, và người dùng có thể kỳ vọng hợp lý rằng tin nhắn cá nhân của họ không bị gửi đi analytics bên ngoài ở dạng thô.
Một vài nguyên tắc đơn giản nên tuân theo ngay từ bây giờ, trước các mô‑đun về bảo mật và Store:
- Thứ nhất, đừng log toàn bộ văn bản tin nhắn của người dùng. Thay vào đó có thể lưu độ dài tin nhắn, loại câu trả lời (số, “có/không”, chọn từ danh sách), hoặc các đặc trưng đã ẩn danh như “câu trả lời trống/không đầy đủ/đã sửa”.
- Thứ hai, đừng log thông tin nhận dạng cá nhân (PII) nếu nó không cần cho logic nghiệp vụ: e‑mail, số điện thoại, địa chỉ, họ tên đầy đủ. Nếu bắt buộc phải dùng, hãy lưu ở một vùng bảo vệ khác và giới hạn truy cập nghiêm ngặt.
- Thứ ba, thận trọng với ngữ cảnh hội thoại. Nếu bạn lưu conversationId, hãy đảm bảo rằng trong analytics bạn không cố “ghép” các hội thoại riêng lẻ thành siêu hồ sơ mà không có lý do chính đáng và cơ sở pháp lý.
- Thứ tư, chú ý đến chính sách của OpenAI và yêu cầu của Store (chúng ta sẽ bàn kỹ trong các mô‑đun về phát hành và bảo mật), nơi nêu rõ dữ liệu nào có thể đưa ra khỏi ChatGPT, dữ liệu nào thì không. Ở giai đoạn thiết kế analytics, hữu ích là xây sẵn cơ chế ẩn danh và tối thiểu hóa dữ liệu để sau này không phải viết lại nửa hệ thống.
Và cuối cùng, hãy nhớ rằng phân tích UX không phải là theo dõi toàn diện và chắc chắn không phải surveillance kiểu Big Brother. Mục tiêu là cải thiện kịch bản và giảm bực bội cho người dùng, chứ không phải xây một bảng điều khiển Big Brother “ai lúc 2:37 sáng đã không đi đến checkout”.
10. Các lỗi thường gặp trong phân tích UX cho workflow
Lỗi số 1: “Chưa lên production, để chỉ số sau”.
Rất thường xuyên, các nhà phát triển chỉ nghĩ về analytics khi App đã được dùng bởi người thật. Kết quả là sự kiện được đưa vào “hậu kỳ”, dữ liệu bị đứt đoạn, và gần như không thể so sánh phiên bản cũ với mới của kịch bản. Một phễu tối thiểu ("workflow_started", "step_started", "step_completed", "workflow_finished") nên được cài ngay từ đầu, khi mã vẫn còn tương đối đơn giản.
Lỗi số 2: Chỉ ghi nhận thành công và bỏ qua lỗi.
Đôi khi log chỉ có "step_completed", còn "step_failed" thì không ai ghi, vì “đáng lẽ nó không được lỗi”. Kết quả là bạn thấy có ít người đến một bước nào đó, nhưng không hiểu là họ tự rời đi hay bị lỗi đá ra. Hãy luôn log cả hoàn tất thành công và thất bại, ít nhất kèm một errorCode thô.
Lỗi số 3: Không gắn với phiên bản workflow.
Bạn thay đổi văn bản, thứ tự bước, đưa vào tool gating, nhưng trong sự kiện thì workflowVersion luôn là "1.0.0". Một tháng sau bạn xem biểu đồ và không thể hiểu cái gì trước thay đổi, cái gì sau đó. Cố định phiên bản kịch bản và, khi cần, biến thể A/B — là thành phần bắt buộc của analytics.
Lỗi số 4: Phân tích quá chi tiết mà không có lý do.
Cực đoan ngược lại — ngay lập tức xây “sơ đồ sự kiện hoàn hảo” với 50 trường, log mỗi cú nhấp từng pixel và từng ký tự gõ lại. Thứ nhất, điều này có thể vi phạm quyền riêng tư. Thứ hai, dữ liệu như vậy khó phân tích và bạn sẽ chìm trong nhiễu. Hãy bắt đầu với một tập sự kiện và chỉ số nhỏ thực sự trả lời các câu hỏi sản phẩm cụ thể, rồi mở rộng khi cần.
Lỗi số 5: Không thống nhất tên bước và kịch bản.
Đôi khi trong mã bước có tên budget, trong analytics — collect_budget, còn trong báo cáo — “bước hỏi về tiền”. Vài tuần sau thì không ai nhớ cái nào là cái nào. Ở giai đoạn thiết kế workflow, nên thống nhất các định danh ổn định cho bước (stepName) và dùng chúng trong UI, log và báo cáo.
Lỗi số 6: Có các chỉ số mà không ai dùng.
Câu chuyện buồn nhất: bạn cẩn thận thu thập rất nhiều dữ liệu, cấu hình gửi sự kiện từ widget và MCP, nhưng không ai mở dashboard hay ra quyết định. Analytics vì analytics thì không cần; luôn tự hỏi: “Tôi có thể ra quyết định gì dựa trên chỉ số này?”. Nếu không có câu trả lời — chỉ số ấy hiện chưa cần.
GO TO FULL VERSION