Coolkid mascot CoolkidLab Build in Public. Level up together.

SEO 菜鳥成長史 · #5

閱讀

GA4 自訂事件實作:7 個事件把監視器升級成「看誰是真讀者」的版本

先講重點

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% 的文章只給你三件事:

問題是:該追哪 7-10 個事件?該怎麼選?scroll 要不要 throttle?outbound 怎麼判斷?萬一 GA 沒載入會不會炸?這些「實際下手的決策」幾乎沒人寫。

這篇給你的是「對個人站/小型內容站」這個 scope 的具體選擇,不是給 e-commerce 或 SaaS 的完整 taxonomy。

2. 為什麼 GA4 內建事件不夠看?(增強測量收了什麼、漏了什麼)

你只裝 gtag 沒加自訂事件時,GA4 收的其實不只 page_view,分兩層:① 自動收集事件——page_view、session_start、first_visit、user_engagement(互動超過 10 秒);② 增強測量(建立網頁串流時通常預設開啟)——scroll(滑到 90%)、外連 click、view_search_results、file_download、影片與表單互動。

看起來增強測量好像都收了,但有兩個缺口:① 顆粒度不夠——scroll 只有 90% 一個檻,分不出「點開就關」和「看了一半」;② 追不到你自己定義的意圖訊號。答不到、或答不夠細的問題:

這些「行為訊號」才是判斷「誰是真讀者」的關鍵。要回答上面這 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點諮詢 CTA1on1 漏斗最頂端的意圖訊號
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 一起自己控;② 自己送 outbound 能拿到乾淨的 link_domain 維度 + 截斷長 URL。如果你不需要這兩點,直接用增強測量內建版就好,不用重做。

4. GA4 自訂事件怎麼用 site.js 實作?(最小可用 pattern)

我整站只有一個 assets/site.js,已經被 page_shell 引入所有頁面。所以加事件邏輯改一個檔,全站生效。

(1)為什麼一律先 typeof gtag === 'function'

GA 載入過程可能被擋(廣告封鎖外掛、CSP 漏配、網路問題)。如果 gtag 沒定義,呼叫它會 throw ReferenceError,整個 script 就掛了——後面的功能也跟著死。

// ❌ 直接呼叫
gtag('event', 'theme_toggle', { mode: cur });

// ✅ 先檢查
if (typeof gtag === 'function') {
  gtag('event', 'theme_toggle', { mode: cur });
}

前者在 GA 沒載的情境會炸。後者 GA 沒載就靜默跳過,網站功能不受影響。這是「event tracking 不該是 critical path」的基本原則。

(2)scroll 要 throttle(不然會卡)

scroll event 一秒可以觸發幾百次。如果每次 scroll 都跑「計算 % + 比對 milestone + 呼叫 gtag」,捲動會明顯卡。要用 requestAnimationFrame throttle:

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 確保每頁只送一次(同個 milestone 不會重送);passive: true 讓瀏覽器不等 listener 就先捲動,畫面更順。

邊界處理:頁面比視窗短時(短文章),scroll% 永遠到不了 50/90,要在 init 時補一次「短頁直接記 90」,否則短文章的閱讀深度資料會全空。

(3)click delegation:一個 listener 處理所有連結

要追 service CTA + outbound 兩種 click,不要對每個 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 (_) {}
});

重點:

(4)dwell 一行解決

setTimeout(() => gtag('event', 'dwell_60s', {
  page_path: location.pathname
}), 60_000);

60 秒後送一次。讀者中途離開頁面也沒關係——GA4 預設會把 queued event 在 unload 時送出,不會掉。

5. 第四刀:GA4 後台「標示為主要事件」

code 上線後 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 面板會即時顯示。

  1. 推 site.js 上線(Vercel 部署完約 1-2 分鐘)
  2. 新分頁打開 coolkidlab.com
  3. GA4 後台 → 報表 → 即時 → 「過去 30 分鐘事件」widget
  4. 回到網站做事件:點 theme toggle → 滑到底 → 等 60 秒 → 點服務 CTA → 切換 GA4 即時面板看
  5. 事件應該在 5-15 秒內陸續出現:theme_toggle、scroll_50、scroll_90、dwell_60s、service_cta_click

如果某個事件沒出現:開 F12 console,輸入 typeof gtag——如果回 function 但事件沒送,那是 listener 沒掛上;如果回 undefined,那是 GA 沒載入(廣告封鎖 / CSP 擋 / network 失敗,三選一)。

7. 戰績 + 我學到什麼

指標做之前做之後
自訂事件數07 ✅
主要事件(轉換)03 ✅
能回答「誰是真讀者」
site.js 增加行數約 +60 行
cache buster bump舊 hash自動(asset_hash 偵測內容變化)

我從這個過程學到三件事:

  1. 「該追哪些事件」是內容策略題,不是技術題。技術只是把策略翻譯成 code。先想清楚「我要回答什麼問題」再寫 listener。
  2. Event tracking 不該影響網站可用性。每個 gtag 呼叫前都要 typeof 檢查——GA 沒載入時網站要還能正常運作。
  3. 事件少而精勝過事件多而亂。7 個事件 + 3 個主要事件,比 30 個事件全部標主要事件好用 10 倍。

8. 給跟我一樣從 0 開始的人:5 步驟 checklist

  1. 列出 5-10 個「想回答的問題」(誰是真讀者?哪些頁有人點 CTA?訂閱漏斗哪一段掉?)
  2. 每個問題對應 1-2 個事件(scroll / dwell / click / submit),不要追動詞太重複的
  3. 在 site.js(或你的全站 JS)加 listener,每個 gtag 呼叫一律 typeof 檢查
  4. Push 上線後,回 GA4 Realtime 面板手動驗證每個事件都送出
  5. 在 GA4 後台只把「跟轉換有關」的 2-3 個事件標主要事件,其他純資料留著
Coolkid AI Lab GA4 過去 7 天統計:31 位活躍使用者、363 次事件、台灣 17 / 美國 7 / 香港 2
事件裝完 7 天的實際數據:31 個活躍使用者 / 363 次事件 / 31 個新使用者。沒這 7 個自訂事件,363 這個數字就只會是 31 個 page_view,全部白看。事件少而精,數據才有訊號。

9. 下一步

GA4 自訂事件裝完,監視器升級成「能告訴你誰是真讀者」的版本。但事件收進來只是「能看」,不是「能用」。真正會用要兩步:

  1. 等 7-14 天累積資料量(個人站每天才 10-50 個訪客,太短沒統計意義)
  2. 在 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)
最常踩
  • 事件名稱用中文導致報表壞掉
  • 重複觸發不去重(一頁打 10 次同事件)
  • dev 測試但沒開 GA4 debug mode

這篇是收斂後寫的版本。
我每兩週寄一封電子報,講「正在做但還沒寫成文章」的東西——
包含每月幫你過濾值得花時間的新 AI 工具,
以及 Lab 新文的個人版(你會比公開版早一週收到)。

→ 訂閱(雙週一封,第一封自動寄起步清單)

跳轉 Substack、隨時取消、不轉賣 email。

如果內容對你有用就太好了
隨喜斗內

Buy Me a Coffee at ko-fi.com
NEXT CHAPTER ▸ #3 GA4 + GSC 終於裝完:CSP 把 GA 擋掉的踩雷

相關閱讀

這篇背後的真實開發過程記錄在 Build Log搜尋標籤:ga4eventsconversionsite-js

本篇為個人學習與實驗紀錄。GA4 介面與事件 API 持續變動,本文 code 範例不保證在你的網站環境完全相同,請依自身狀況實驗驗證。本站不接 YMYL 高風險站、不做 PBN、不做品牌矩陣 SEO。

← 回 SEO 菜鳥成長史

⚠ 本站所有內容僅供教育與研究用途,不構成投資建議,不保證任何獲利。投資有風險,使用者須自行判斷並承擔結果。