前兩篇我們先把 Signal 轉成事件,再用 Product Analytics 開始分析。
到這裡,很容易出現一個新的問題:如果我們之後真的要用這些資料做產品決策,那這些資料本身可信嗎?
這個問題其實非常工程師。
我們平常不會因為某個 API 回傳了一次正確結果,就認為整個系統沒有問題;資料追蹤也一樣。事件有送出去,不代表它一定沒有重複、沒有漏掉,也不代表不同人對同一個事件的理解完全一致。
最常見的狀況之一,就是同一件事被記了兩次。
例如 Checkout 完成後,前端收到成功結果時送了一次:
posthog.capture('purchase_completed', {
order_id,
})
後端為了確保資料完整,也在訂單真正建立時送了一次同名事件。
兩邊各看起來都合理,最後 Product Analytics 裡的訂單數卻變成資料庫的兩倍。
這時候問題不在 PostHog,也不在圖表,而是在我們沒有先定義:到底哪一個系統有資格宣告這件事情真的發生?
對付款完成、訂單建立、檔案處理完成這類有明確後端結果的事件,我通常會傾向由 Server-side 記錄,因為它更接近真正的業務結果,也不容易受到瀏覽器關閉、網路中斷或廣告阻擋工具影響。
相反地,像是「使用者展開一個區塊」、「切換頁籤」、「點開說明」這類 UI 行為,本來就只存在前端,由 Client-side 記錄會比較自然。
重點不是 Server-side 永遠比較好,而是要清楚知道事件代表什麼,以及它最適合在哪裡被確認。
另一種狀況是資料比預期少。
假設資料庫有 1,000 筆完成訂單,但 PostHog 只有 920 個 purchase_completed。
如果事件是從瀏覽器送出,原因可能很多:
因此,對真正重要的 Product Metric,不要只確認「程式碼裡有 capture()」。
實際測試時,可以打開瀏覽器的 Network,確認事件是否真的送出;也可以到 PostHog 裡查看最近收到的事件,確認 Event Name、Property 與使用者是否符合預期。
如果我們有一個對產品很重要的事件,例如前一篇說的 Activation Event,更值得刻意走過幾次完整流程,確認它在成功時會出現、失敗時不會出現。
另一個常見問題和 Identity 有關。
PostHog 在使用者還沒登入時,可以先用匿名的 distinct_id 記錄事件;使用者登入後,我們通常會透過 identify() 把後續事件和真正的 User ID 關聯起來。
posthog.identify(user.id)
這裡應該使用穩定、唯一,而且不會因為使用者修改資料而改變的 ID。
例如 Email 雖然看起來很方便,但使用者可能會更換 Email;如果拿它當成身份本身,長期下來就比較容易產生問題。
Identity 一旦亂掉,很多分析都會受到影響。Retention 可能把同一個人當成兩個人,Funnel 也可能看起來像是使用者走到一半就消失了。
還有一種問題非常不起眼:工程師自己。
PostHog 官方建議將測試環境與正式環境分開,使用不同的 Project,但我們仍有可能需要在正式環境進行測試。
工程師可能會產生很多測試資料,如果產品流量還很小,一個工程師測試 Checkout 50 次,甚至可能直接把當天的轉換率扭曲掉。
我們可以在設定中建立篩選器來標記測試帳號。例如如果使用 Clerk,可能對於 <text>+clerk_test@<domain> 的測試格式不陌生,我們可以直接排除掉:

也可以利用另外一個功能:Cohorts,他有預先建立好 Internal / Test Users,修改定義即可。


看到這裡,很容易走向另一個極端:希望 PostHog 的每一個數字都和資料庫完全一致。
但 Analytics 不一定需要成為 Production Database 的完整複製品。
例如 Web Analytics 的 Pageview 本來就可能因為阻擋工具而少一部分;有些 UI 行為也沒有必要追求財務系統等級的精確性。
真正需要問的是:
這個資料準不準,會不會影響我們接下來要做的決策?
如果只是想知道某個新功能大概有沒有人在用,少掉少量事件可能不會改變結論。
但如果我們準備用 purchase_completed 判斷實驗成敗,或者用某個事件定義 Activation,那麼資料品質就值得投入更多時間確認。
資料不是因為出現在漂亮的圖表裡就自動變成事實。
接下來,我們會先挑一個很常見、也很適合工程師開始關注的產品問題:新使用者到底有沒有真的開始取得產品價值?
下一篇,我們來看看 Activation,以及如何用 Funnel 找到「註冊」和「真正開始成功」之間的差距。
如果你願意花 30 秒留下回饋,我會用這些意見來調整後續文章:分享你的意見
