GA4 自訂事件實作:7 個事件看誰是真讀者
文 / Coolkid發布:2026-05-11 · 最後更新:2026-08-07閱讀約 11 分鐘

摘要
GA4(Google 流量分析)的增強測量夠用嗎,要不要加自訂事件?裝好就有增強測量,自動收 page_view、捲動 90%、外連點擊、檔案下載,但這些都是通用事件,追不到你自己定義的意圖,像是諮詢 CTA、訂閱、主題切換,捲動也只有 90% 沒有 50%。我加了 7 個自訂事件補這一塊,事件怎麼選比數量重要。
先講一件我一開始也搞錯的事。GA4 裝好不是只追 page_view。
它預設就有自動收集加增強測量,連捲動到 90%、外連點擊、檔案下載都會自動收集。
但這些都是通用事件。它答不出「他點到我的諮詢 CTA 沒、訂電子報沒、停超過 1 分鐘沒」這種我自己定義的行為。
這篇紀錄我在 site.js 加 7 個自訂事件的完整實作。
選哪些事件、怎麼寫 JS、為什麼要用 typeof gtag 守衛、怎麼在 GA4 後台標示為主要事件、怎麼用 Realtime 驗證有沒有真的送出。
這是 #4 預告過的續集。
終於把監視器升級成能告訴你誰是真讀者、誰只是路過的版本。
1. 為什麼這篇值得寫
GA4 自訂事件教學一抓一大把,但 90% 的文章只給你三件事:
- 「在 head 貼這段 gtag」
- 「呼叫 gtag('event', '...', {{...}})」
- 「在 GA4 後台標示為主要事件」
問題是,該追哪 7 到 10 個事件?該怎麼選?捲動要不要限制頻率?外連怎麼判斷?萬一 GA 沒載入會不會炸?
這些真正要下手時的決策,幾乎沒人寫。
這篇給你的是個人站跟小型內容站的具體選法,不是給電商或 SaaS 用的完整分類體系。
2. 為什麼 GA4 內建事件不夠看?(增強測量收了什麼、漏了什麼)
你只裝 gtag、沒加自訂事件的時候,GA4 收的其實不只 page_view,分成兩層。
第一層是自動收集事件,page_view、session_start、first_visit、user_engagement(互動超過 10 秒)。
第二層是增強測量,建立網頁串流時通常預設開啟,收的是捲動到 90%、外連點擊、站內搜尋、檔案下載,還有影片與表單互動。
看起來增強測量好像都收了,但有兩個缺口。
第一個是顆粒度不夠。捲動只有 90% 一個門檻,分不出「點開就關」跟「看了一半」。
第二個是追不到你自己定義的意圖訊號。像下面這幾個問題,它答不到,或是答得不夠細:
- 他是看完才走,還是開頭就關
- 他停了 5 秒還是 5 分鐘
- 他點到我的服務 CTA 沒
- 他切了深色模式沒、訂閱表單送出沒(自訂互動,GA 內建不會收)
這些行為訊號,才是判斷誰是真讀者的關鍵。要回答上面這 4 個問題,至少要自訂 7 個事件。
3. GA4 該追蹤哪 7 個自訂事件?(選擇邏輯)
GA4 的自訂事件上限是 50 個,看起來很多,但每加一個就多一份維護成本。對個人內容站來說,這 7 個夠用:
| 事件名 | 觸發 | 為什麼追 |
|---|---|---|
scroll_50 | 滑到 50% | 區分「點開就關」vs「至少看一半」 |
scroll_90 | 滑到 90% | 真讀者(讀到底) |
dwell_60s | 停 60 秒 | 真讀者 vs 路過(10 秒 user_engagement 太寬) |
service_cta_click | 點諮詢 CTA | 1on1 漏斗最頂端的意圖訊號 |
outbound_click | 點站外連結 | 看讀者跳到哪、引用哪些工具 |
subscribe_submit | 訂閱 form 成功送出 | Email 收集漏斗末端 |
theme_toggle | 切淺/深色 | 視覺設計決策依據(多少人真的會切) |
這 7 個分成三類,閱讀深度(scroll 跟 dwell)、意圖訊號(cta 跟 subscribe)、行為觀察(outbound 跟 theme)。每一類至少要有 2 個,才能交叉看。
誠實揭露一下。這 7 個裡面,scroll_90 跟 outbound_click 其實跟 GA4 增強測量本來就會收的 scroll 和 click 重疊。
我還是自己送,有兩個原因。我要 scroll_50 這個中間門檻,增強測量只有 90%,乾脆 50 跟 90 一起自己控。自己送外連也能拿到乾淨的 link_domain 維度,順便截斷過長的網址。
如果你不需要這兩點,直接用增強測量本來就有的版本就好,不用重做一次。
4. GA4 自訂事件怎麼用 site.js 實作?(最小可用 pattern)
我整站只有一個 assets/site.js,已經被 page_shell 引入所有頁面。所以加事件邏輯只要改一個檔,全站生效。
(1)為什麼一律先 typeof gtag === 'function'
GA 載入的過程可能被擋,廣告封鎖外掛、CSP 漏配、網路問題都有可能。
如果 gtag 沒定義,呼叫它會丟出 ReferenceError,整個 script 就掛了,後面的功能也跟著死。
// ❌ 直接呼叫
gtag('event', 'theme_toggle', { mode: cur });
// ✅ 先檢查
if (typeof gtag === 'function') {
gtag('event', 'theme_toggle', { mode: cur });
}
前者在 GA 沒載入的時候會炸。後者 GA 沒載就安靜跳過,網站功能完全不受影響。
追蹤程式碼不該擋在網站的關鍵路徑上。
(2)scroll 要 throttle(不然會卡)
捲動事件一秒可以觸發幾百次。如果每次捲動都跑一輪「算百分比、比對里程碑、呼叫 gtag」,畫面會明顯卡。
所以要用 requestAnimationFrame 限制觸發頻率:
const fired = new Set();
let ticking = false;
function checkScroll() {
ticking = false;
const pct = (window.scrollY + window.innerHeight)
/ document.documentElement.scrollHeight * 100;
for (const m of [50, 90]) {
if (pct >= m && !fired.has(m)) {
fired.add(m);
gtag('event', 'scroll_' + m, { page_path: location.pathname });
}
}
}
window.addEventListener('scroll', () => {
if (!ticking) { requestAnimationFrame(checkScroll); ticking = true; }
}, { passive: true });
兩個重點。fired 這個 Set 確保每頁只送一次,同一個里程碑不會重送。passive: true 讓瀏覽器不等你的 listener 就先捲動,畫面更順。
還有一個邊界要處理。頁面比視窗還短的時候,捲動百分比永遠到不了 50 或 90。
所以要在初始化的時候補一次「短頁直接記 90」,否則短文章的閱讀深度資料會全部是空的。
(3)click delegation:一個 listener 處理所有連結
要追 service CTA 跟外連兩種點擊,不要對每個 a 標籤都掛 listener。頁面有幾十個連結的時候,記憶體會吃緊。
document.addEventListener('click', (e) => {
const a = e.target.closest('a');
if (!a) return;
const href = a.getAttribute('href') || '';
// Service CTA
if (href.includes('contact.html')
&& href.includes('topic=consultation')) {
gtag('event', 'service_cta_click', {
page_path: location.pathname,
link_text: (a.textContent || '').trim().slice(0, 60),
});
}
// Outbound
try {
const url = new URL(a.href, location.href);
if (url.host && url.host !== location.host) {
gtag('event', 'outbound_click', {
link_domain: url.host,
link_url: url.href.slice(0, 200),
});
}
} catch (_) {}
});
重點:
- service CTA 用 href 偵測(href 包含 contact.html?topic=consultation)。比 class selector 穩——之後改 button 樣式不會壞
- outbound 用 URL 解析(new URL(...))比 startsWith('http') 安全——能處理相對路徑、anchor 等邊界
- url.href.slice(0, 200) 避免送超長 URL 進 GA(GA event param 有長度上限)
(4)dwell 一行解決
setTimeout(() => gtag('event', 'dwell_60s', {
page_path: location.pathname
}), 60_000);
60 秒後送一次。讀者中途離開頁面也沒關係,GA4 預設會把排隊中的事件在頁面卸載時送出,不會掉。
這一條是七個裡面最簡單的。
5. 第四步:GA4 後台「標示為主要事件」
程式碼上線後 GA4 會自動收事件,但那只是「事件」。要轉成「主要事件」,也就是轉換,才會進報表的轉換欄。
路徑是 GA4 管理 → 資料顯示欄 → 事件 → 找到事件名 → 切換右側的「標示為主要事件」。
我這 7 個事件的標示策略:
策略比清單本身重要。
| 事件 | 標示為主要事件? |
|---|---|
service_cta_click | ✅ 主要事件(=潛在客戶) |
subscribe_submit | ✅ 主要事件(=Email 取得) |
scroll_90 | ✅ 主要事件(=完讀,作為內容品質訊號) |
scroll_50 / dwell_60s | ❌ 當「參與訊號」,不算轉換 |
outbound_click / theme_toggle | ❌ 當「行為觀察」,純資料 |
重點是不要把所有事件都標成主要事件。標太多會讓 GA4 的轉換報表失焦,看不出哪一個才值得追。
標 3 個就夠了。
6. 第五步:驗證(GA4 Realtime)
GA4 自訂事件最麻煩的地方,是你看不到事件有沒有真的送出,要等 24 小時後標準報表才有資料。
但 Realtime 面板會即時顯示,可以當場驗證。
- 推 site.js 上線(Vercel 部署完約 1-2 分鐘)
- 新分頁打開 coolkidlab.com
- GA4 後台 → 報表 → 即時 → 「過去 30 分鐘事件」widget
- 回到網站做事件:點 theme toggle → 滑到底 → 等 60 秒 → 點服務 CTA → 切換 GA4 即時面板看
- 事件應該在 5-15 秒內陸續出現:theme_toggle、scroll_50、scroll_90、dwell_60s、service_cta_click
如果某個事件沒出現,開 F12 console,輸入 typeof gtag。
如果回傳 function 但事件沒送,那是 listener 沒掛上。如果回傳 undefined,那是 GA 根本沒載入,廣告封鎖、CSP 擋掉、網路失敗,三選一。
7. 戰績 + 我學到什麼
| 指標 | 做之前 | 做之後 |
|---|---|---|
| 自訂事件數 | 0 | 7 ✅ |
| 主要事件(轉換) | 0 | 3 ✅ |
| 能回答「誰是真讀者」 | ❌ | ✅ |
| site.js 增加行數 | — | 約 +60 行 |
| cache buster bump | 舊 hash | 自動(asset_hash 偵測內容變化) |
我從這個過程學到三件事:
有一件事我事後才想通。
- 「該追哪些事件」是內容策略題,不是技術題。技術只是把策略翻譯成 code。先想清楚「我要回答什麼問題」再寫 listener。
- Event tracking 不該影響網站可用性。每個 gtag 呼叫前都要 typeof 檢查——GA 沒載入時網站要還能正常運作。
- 事件少而精勝過事件多而亂。7 個事件 + 3 個主要事件,比 30 個事件全部標主要事件好用幾倍。
8. 給跟我一樣從 0 開始的人:5 步驟 checklist
- 列出 5-10 個「想回答的問題」(誰是真讀者?哪些頁有人點 CTA?訂閱漏斗哪一段掉?)
- 每個問題對應 1-2 個事件(scroll / dwell / click / submit),不要追動詞太重複的
- 在 site.js(或你的全站 JS)加 listener,每個 gtag 呼叫一律 typeof 檢查
- Push 上線後,回 GA4 Realtime 面板手動驗證每個事件都送出
- 在 GA4 後台只把「跟轉換有關」的 2-3 個事件標主要事件,其他純資料留著
9. 下一步
GA4 自訂事件裝完,監視器就升級成看得出誰是真讀者的版本。
但事件收進來只是能看,不是能用。真正要用得起來還有兩步:
- 等 7-14 天累積資料量(個人站每天才 10-50 個訪客,太短沒統計意義)
- 在 GA4「探索」報表設兩個自訂分析:(a) 每篇文章的 scroll_90 完讀率排名 (b) service_cta_click 的來源頁面分布
白老鼠實驗下一篇 #6 會回到 GSC,看一週後的索引曲線。
強送配額分散送之後,曲線會不會變平緩、未索引的頁有沒有自然進索引、第一個搜尋查詢出現了沒。
名詞解釋
- GA4(Google Analytics 4)
- Google 的流量分析工具:訪客從哪來、看了什麼、停多久。GSC 管「搜尋結果上的表現」,GA4 管「進站後的行為」。
- SEO(搜尋引擎優化)
- 讓網站在 Google 搜尋結果排得更前面的一整套方法,涵蓋技術體質、內容品質、連結結構三層。
- GSC(Google Search Console)
- Google 給網站主的免費後台:看自己網站在搜尋的曝光、點擊、排名跟索引狀態。做 SEO 的人天天開的儀表板。
- Threads
- Meta 旗下的文字社群平台。本站的社群引流主戰場之一,相關自動發文流程有整篇教學。
- 曝光(impression)
- 你的頁面出現在搜尋結果裡被看到的次數,不管有沒有被點擊。
- 自然流量(organic traffic)
- 從搜尋結果免費點進來的流量,相對於買廣告來的流量。
- 點閱率(CTR, Click-Through Rate)
- 看到你的搜尋結果的人裡,實際點進來的比例。曝光 100 次、被點 5 次,CTR 就是 5%。
- 跳出率(bounce rate)
- 進站後只看一頁、沒有任何互動就離開的訪客比例。GA4 的算法跟舊版 GA 不同,比較時要對齊定義。
- GEO(生成式引擎優化)
- 讓 ChatGPT、Perplexity 這類 AI 在回答問題時引用你網站內容的優化方法,是 SEO 在 AI 時代的延伸戰場。
- 行動呼籲(CTA, Call to Action)
- 頁面上引導你做下一步的元素,像「訂閱」「立即開始」那顆按鈕。
- 引薦流量(referral)
- 從其他網站的連結點進來的流量。ChatGPT 引用你的內容帶來的點擊就屬於這一類。
- 搜尋結果頁(SERP)
- 在 Google 搜一個詞之後出現的那一整頁結果,包含一般結果、精選摘要、AI 摘要等版位。
看完這篇之前先確認:
- GA4 已部署但只看到 page_view
- 想追 CTA click / scroll 深度
- 想用 GA4 取代付費分析工具
- 連 GA4 都還沒裝的人
- 想用 GTM UI 點點點不寫 code 的人
- 結構複雜的電商(建議直接上 GTM)
相關閱讀
這篇背後的真實開發過程記錄在 Build Log。
搜尋標籤:ga4、events、conversion、site-js。
本篇為個人學習與實驗紀錄。GA4 介面與事件 API 持續變動,本文 code 範例不保證在你的網站環境完全相同,請依自身狀況實驗驗證。本站不接 YMYL 高風險站、不做 PBN、不做品牌矩陣 SEO。
