Đo lường: Google Tag Manager
Toàn hệ dùng một container duy nhất: GTM-MZ6DXZZ3. Khai ở đúng một chỗ cho mỗi cụm (app/env.public.ts), và mọi chỗ khác re-export từ đó.
| Cụm | Nạp GTM | Nạp ở đâu |
|---|---|---|
www.conan.school | có | app/root.tsx, snippet trong <head> + <noscript> iframe |
tokyo.conan.school | có (từ 09.09.2026) | app/components/GoogleTagManager.tsx + app/lib/gtm.ts |
admin, mam, play, video, docs | không | công cụ nội bộ, không đo |
Vì sao tokyo không chép được snippet của www
Ba khác biệt, và cả ba đều đổi cách viết mã:
Tokyo là SPA. Đổi trang không nạp lại tài liệu, nên lượt xem trang tự động của GTM chỉ nổ một lần trong cả phiên. GoogleTagManager.tsx vì thế tự đẩy page_view ở mỗi lần đổi đường dẫn. Thiếu điều này thì báo cáo nói mỗi người dùng xem đúng một trang rồi thôi, một con số trông hợp lý nên không ai nghi ngờ.
Cùng một ứng dụng phục vụ inside6.com. Đó là thương hiệu khác. initGtm() từ chối chạy khi host kết thúc bằng inside6.com; trộn hai tài sản đo lường vào một container thì không tách ra lại được.
Dev không đẩy vào container thật. import.meta.env.DEV chặn ở cùng chỗ đó.
Không có <noscript> iframe ở tokyo: không có JavaScript thì cả ứng dụng không chạy, nên không có gì để đo.
Luật: dataLayer không mang thông tin định danh
Chỉ user_id. Không email, không tên, không số điện thoại.
Mọi thứ đẩy vào dataLayer đều rời trình duyệt sang Google, và từ đó một tag cấu hình sai ở phía GTM là đủ để nó đi tiếp sang bên thứ ba, trong khi mã nguồn không có gì đổi để mà rà ra. Cần ghép danh tính thì ghép ở phía sau bằng user_id, nơi dữ liệu còn nằm trong tay mình.
Ba chỗ hỏng đã có thật (rà soát 09.09.2026)
- tokyo khai
GTM_IDmà không nạp gì. Hằng số nằm trongenv.public.tsnhiều tháng, không file nào nạpgtm.js. Cụm trông như đã cài, đây là loại hỏng tệ nhất: không có lỗi, không có trang trắng, chỉ có một tập dữ liệu bằng không mà không ai đi tìm. - www khai container ở hai file cùng được import.
env.public.ts(thời Next,@/) vàapp/env.public.ts(~/) cùng khaiGTM-MZ6DXZZ3. Trùng giá trị nên vô hình, cho tới ngày đổi container, sửa một bản, và một nửa số trang lặng lẽ báo về container cũ. Đã sửa: bản gốcexport { GTM_ID } from './app/env.public'. - Email và tên người học đi vào
dataLayer.hooks/useActivityTracker.tsđẩyuser_email,$email,$nametrongsession_startvàidentify_user. Đã gỡ, chỉ cònuser_id.
Còn một mảnh chưa dọn: www.conan.school/components/tracking/GoogleTagManager.tsx là bản GTM viết cho Next (import Script from 'next/script', mà next/script không nằm trong bảng alias của vite.config.ts, import là build gãy). Không ai dùng, nhưng nó chép lại đúng snippet đang chạy, nên người sau vào "sửa GTM" rất dễ sửa nhầm bản chết.
Gác
npm run check:analyticsChạy trong job guards của CI. Ba điều: mỗi cụm khai container ở nhiều nhất một file; cụm nào khai thì phải có chỗ nạp thật googletagmanager.com/gtm.js; và ruột của mọi dataLayer.push(…) / trackEvent(…) không chứa khoá định danh. Gác chỉ soi ruột của lượt đẩy chứ không soi cả file, một trang nói về số điện thoại trong nội dung không phải là một trang gửi số điện thoại sang Google, và một gác kêu ở đó là một gác người ta học cách bỏ qua.
Gác dùng git grep --untracked: file vừa thêm mà chưa commit vẫn là mã sắp chạy. Không có cờ đó thì gác bỏ qua đúng những file mà PR đang thêm vào, tức xanh ở đúng lần duy nhất nó cần đỏ.