GA4 + GSC 終於裝完:CSP 把 Google Analytics 擋掉的踩雷全紀錄
從 v0.3 上架到今天剛好第 5 天。終於把 GA4 + GSC 都裝上去。
原本以為是「複製貼上 5 分鐘」的小事。實際做完才發現中間有個讓我笑出來的鍋——是我自己半個月前埋的。
這篇紀錄整套裝 GA4 + GSC 的步驟、踩到的 CSP 陷阱、以及這個陷阱怎麼讓 28 個頁面的 GA 一起啞掉。
1. 為什麼這篇值得寫
GA4 安裝教學一抓一大把,但 95% 的文章只講三件事:
- 進 GA4 建立資源
- 複製 gtag 程式碼
- 貼到網站 裡,完成
對於用 WordPress + 外掛的人,這樣確實 5 分鐘就好。但靜態站、自己 build、又有資安潔癖鎖了 CSP 的人——你會發現貼進去之後 console 一片紅,GA 完全沒反應,然後查半天還以為是自己貼錯位置。
這篇的核心不是「怎麼貼 GA」,是「為什麼貼了 GA 卻沒反應」、以及「GA + GSC 的整套裝法」。
2. 第一刀:GA4 帳戶開到拿 G ID(10 分鐘)
GA4 後台流程乾淨,跟著走基本不會出錯:
- 進 analytics.google.com → 建立帳戶 → 帳戶名稱填品牌名
- 建立資源 → 屬性名稱填品牌名(不要塞 URL 或「GA4」字樣,這是給自己之後辨識用的標籤)
- 時區選台灣、貨幣選新台幣
- 業務目標問你想看什麼,按需求勾
- 資料串流選「網站」→ 填 URL 跟串流名稱
走完會拿到一組 G-XXXXXXXXXX 開頭的 Measurement ID,這個 ID 一輩子不會變,複製存好。
後台會跳一個 modal 給你 gtag.js 的安裝程式碼。這段才是真正的戰場。
3. 第二刀:CSP 把 GA 擋掉的鍋(這篇的主菜)
我這站的 head 不是手動寫每一頁,是有 build.py 一次注入所有頁面。所以「貼程式碼」實際上是改 page_shell() 函式裡 head 的 template。
把 GA4 的 ID 拉成常數放檔頂,head template 在 </head> 之前加兩段:
GA4_ID = "G-XXXXXXXXXX"
# 在 page_shell() 的 </head> 之前
<script async src="https://www.googletagmanager.com/gtag/js?id={GA4_ID}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{GA4_ID}');
</script>
跑 python build.py,28 個 html 全部重生,每頁都帶 G ID。git push,Vercel 自動部署。回 GA4 後台等資料。
等了 5 分鐘——還是 0。打開網站,按 F12 開 console,畫面一片紅:
Refused to load the script
'https://www.googletagmanager.com/gtag/js?id=G-XXXX'
because it violates the following Content Security Policy directive:
"script-src 'self' 'unsafe-inline'"
兇手就很明顯了。是我半個月前在 vercel.json 鎖的 CSP(資安潔癖的鍋)。當時的 script-src 只允許「來自自家站」跟「inline」兩種來源,googletagmanager.com 不在白名單裡,瀏覽器直接拒載。
(1)什麼是 CSP
Content-Security-Policy 是 HTTP header,告訴瀏覽器「這個網站只准載入哪些來源的 script / style / 圖 / 字體 / 連線」。鎖緊了能擋掉 XSS 攻擊跟惡意第三方腳本,但鎖太死自己想用的服務也會被鎖在門外。
vercel.json 裡的 CSP 大概長這樣(節選):
"Content-Security-Policy":
"default-src 'self';
script-src 'self' 'unsafe-inline';
... (其他 directives)"
GA 要載 gtag.js(外部 script)、又要把資料 POST 回 google-analytics.com(外部 connect),這兩個權限都要顯式開放。
(2)正確的 CSP 修法
丟給 agent 一次改完 vercel.json,把兩個 directive 加上 GA 相關的網域:
script-src 'self' 'unsafe-inline'
https://www.googletagmanager.com;
connect-src 'self'
https://*.supabase.co
https://www.google-analytics.com
https://*.analytics.google.com
https://*.googletagmanager.com;
重點:
- script-src 加 googletagmanager.com(載 gtag.js 的地方)
- connect-src 加 google-analytics + analytics.google + googletagmanager 三個(GA 上報資料的端點)
- img-src 已有 https: 涵蓋 GA pixel,不用改
重新 commit、push。Vercel 部署完,回網站重整、F12 console 一片乾淨。GA4 後台「過去 30 分鐘活躍使用者」終於亮 1——那 1 個就是我自己。
4. 第三刀:GSC 串接 + sitemap 提交 + 資料保留
GA 跑起來只是第一塊。要看到「有人從 Google 搜尋什麼進站」要把 GSC 串進來。三件小事一次做:
(1)GA4 ↔ GSC 串接
GA4 後台 → 管理(左下齒輪)→ 產品連結 → Search Console 連結 → 選 GSC 資源 → 選網站串流 → 提交。
串完之後,GA 報表會多兩塊:「探索 → 範本庫 → Search Console 報表」可以看查詢字、CTR、平均排名;「獲客 → 流量獲取」會多一條 google / organic 細分到具體搜尋查詢。
為什麼一定要串:原本 GSC 只能看「誰找到我」,GA 只能看「進來之後幹嘛」,兩邊資料各看各的。串接後接在一起——找到我的查詢字,配上他進站後的停留 / 互動 / 轉換——這才是 SEO 真正能拿來判斷的數字。
(2)GSC 提交 sitemap
GSC 後台 → 索引 → Sitemap → 加新的 sitemap → 輸入「sitemap.xml」→ 提交。一次解掉「Google 知不知道我的站有哪些頁」這個問題。
提醒:sitemap 提交不等於「立刻被收錄」。GSC 會跟你說「成功讀取」就好,實際進索引還要等幾天到幾週。這個我之前 #1 那篇有寫過完整流程。
(3)資料保留改 14 個月
GA4 預設「事件層級資料」只保留 2 個月。對個人站等於每兩個月就洗掉一次歷史,看不到趨勢。
GA4 後台 → 管理 → 資源設定 → 資料保留 → 改 14 個月(免費上限)。這個沒成本沒副作用,所有人都該開到滿。
5. 最終戰績
| 項目 | 做完前 | 做完後 |
|---|---|---|
| GA4 安裝 | 未裝 ❌ | 28 頁全帶 ✅ |
| GSC 串接 | 未串 ❌ | 已串 ✅ |
| Sitemap 提交 | 未提交 ❌ | 已提交 ✅ |
| 資料保留 | 2 個月(預設) | 14 個月 ✅ |
| CSP whitelist | 太緊 ❌ | 正確開放 GA 端點 ✅ |
6. 我從這個過程學到什麼
三件事:
- 「複製貼上 5 分鐘」的教學文,前提是「跟教學文寫的環境一樣」。我有自己的 build 系統 + 自己鎖過的 CSP,原本的範本就會卡。
- 出問題第一步打開 F12 console。瀏覽器幾乎一定會把擋掉的請求印出來告訴你原因,不用猜。
- 同一次 commit 修兩個檔(build.py + vercel.json)才能上線。少改一個 push 上去 GA 就裝了等於沒裝,浪費一次部署。
這跟我做交易學到的東西一樣:訊號出現不代表能直接下單,要看跟你的部位 / 環境合不合。一個普世的 setup,遇到自己的特殊環境一樣會卡。
7. 給跟我一樣從 0 開始的人:6 步驟 checklist
如果你的站也準備裝 GA4 + GSC,按這個順序走:
- GA4 後台建立資源、拿到 G-XXXXXXXXXX
- 把 gtag.js script 加到網站 (靜態站找你的 head template / build script,不要每個 html 手貼)
- 如果有設 CSP,script-src 加 https://www.googletagmanager.com、connect-src 加三個 GA 端點
- Push 上線,回 GA4 後台「過去 30 分鐘」看自己有沒有亮起來;沒亮就 F12 看 console 找原因
- GA4 ↔ GSC 串接、GSC 提交 sitemap、資料保留改 14 個月,三件事一次做完
- 確認 robots.txt 沒擋 Googlebot、sitemap.xml URL 都是 200
整套順利做完大概 30 分鐘。我這次因為踩了 CSP 鍋,多花了大概 20 分鐘。但下一次任何站都不會再被同一個鍋打到。
8. 下一步
GA + GSC 裝完只是「裝好監視器」。預設只追 page_view,看得到「有沒有人來」,但看不到「他來了之後幹嘛」。
白老鼠實驗下一篇 #4 會做自訂事件 + 轉換追蹤:定義「滑到底」「點 CTA」「停留 60 秒以上」這些行為訊號,再標哪些算重要事件、哪些算轉換。等於把監視器升級成「能告訴你誰是真讀者、誰只是路過」的版本。
看完這篇之前先確認:
- 剛裝 GA4 但 console 一片紅的人
- 用 Vercel + 自己鎖 CSP 的靜態站
- GA + GSC 想一次到位的人
- 完全還沒裝 GA4 的人(先看 #0 gsc-basics)
- 用 Plausible / Umami 等替代分析的人
- WordPress + 外掛全自動的人
- 只開 google.com 忘了 googletagmanager.com
- 改完 vercel.json 沒重新 deploy
- 漏掉 fonts.googleapis.com / gstatic.com
相關閱讀
- #0 什麼是 GSC?新手如何看懂 Google Search Console
- #1 sitemap 提交 GSC 跳「無法擷取」是壞了嗎?
- #2 PageSpeed 效能 67 → 93:三輪優化全紀錄
這篇背後的真實開發過程記錄在 Build Log。
搜尋標籤:ga4、gsc、csp、vercel。
本篇為個人學習與實驗紀錄。GA4 / GSC 介面與 CSP 規範持續變動,本文步驟不保證在你的網站環境完全相同,請依自身狀況實驗驗證。本站不接 YMYL 高風險站、不做 PBN、不做品牌矩陣 SEO。