FB 流量網址多亂碼!1 段 JS 清掉污染 GA 報表的 ?v= 參數

你有沒有發現,從 Facebook 廣告進來的流量,網址尾巴總是被加上一串像 ?v=1a2b3c4d5e 的亂碼?這些參數不是你親手埋的 UTM,而是 Facebook 自己偷偷加上去的。結果就是 GA 報表裡同一個頁面被拆成好幾筆獨立網址,跳出率變形、平均工作階段時間失準,所有內容分析全部被打亂。

更麻煩的是,這些參數不請自來、無法從廣告後台關閉,手動篩選又費時費力。下面這段 JS 是我在好幾個客戶的 WordPress 網站上實戰驗證過的方法,只要一段腳本就能在瀏覽器端把 ?v= 清掉,讓你的 GA 資料立刻恢復乾淨。

為什麼 FB 廣告網址會被加上 ?v= 亂碼?

Facebook 廣告系統為了確保每次點擊都使用最新的 Pixel 設定、防止瀏覽器或 CDN 快取干擾,會在連結後方自動附加一個版本雜湊值。這個值通常是 8 碼以上的十六進制字串,特徵非常明顯:只有一個 v 參數,後面接長得像 a1b2c3d4e5f6 的亂碼。它不是傳統的 fbclid,也不會出現在廣告報表的網址參數設定裡,因此經常被忽略。

對 Google Analytics(通用版或 GA4)來說,每個不同的網址參數就是一個獨立的頁面。當同一個部落格文章在報表裡出現 /post/?v=abc123、/post/?v=def456、/post/ 三種版本時,你的自然流量、廣告成效與內容互動數據就會被切割得七零八落,無法正確判斷哪個版本才是真正的績效。

一段 JS 清除 ?v= 參數,讓 GA 報表不再被污染

核心邏輯很簡單:在頁面載入時偵測網址列是否含有符合 Facebook 特徵的 ?v= 參數,如果有,就用 history.replaceState 把它移除。這個 API 的好處是不會重新載入頁面、不觸發任何跳轉,也不會干擾 Facebook Pixel 已經發出的請求。

以下是完整的 JavaScript 程式碼,你可以直接使用:

<script>
(function() {
  const url = new URL(location.href);
  const vParam = url.searchParams.get('v');
  
  // 偵測是否為 Facebook Pixel 特徵版本碼(hash 類型)
  if (vParam && /^[a-f0-9]{8,}$/i.test(vParam)) {
    console.warn('[WP-DEBUG] 偵測到 Facebook Pixel 加入的 ?v= 參數:', vParam);
    
    // 保留原本的 path 與錨點,不重整頁面
    const cleanUrl = url.pathname + url.hash;
    history.replaceState(null, '', cleanUrl);
    console.info('[WP-DEBUG] 已清除 URL 汙染參數 ?v=,新網址:', cleanUrl);
  } else {
    console.log('[WP-DEBUG] 未發現 Facebook 特徵型的 ?v= 參數,無需處理。');
  }
})();
</script>

💡 這個方法為什麼特別適合 WordPress 接案?

  • • 不需要更動 Facebook 廣告設定,也不需要客戶提供企業管理平台權限
  • • 完全在前端執行,不拖慢主機回應速度,也不會和任何 SEO 外掛衝突
  • • 同時保護 GA 數據,又保留錨點與頁面狀態,使用者體驗零影響

如何將這段 JS 放進 WordPress 網站?

最穩妥的做法是透過佈景的 functions.php 將腳本注入 wp_footer 勾點,不需要直接去改 header.php 或 footer.php。這樣做有兩個好處:一是佈景更新後腳本不會消失,二是可以集中管理所有客製程式碼。範例如下:

add_action('wp_footer', function() {
  ?>
  <script>
  (function() {
    const url = new URL(location.href);
    const vParam = url.searchParams.get('v');
    if (vParam && /^[a-f0-9]{8,}$/i.test(vParam)) {
      console.warn('[WP-DEBUG] 偵測到 Facebook Pixel ?v= 參數:', vParam);
      const cleanUrl = url.pathname + url.hash;
      history.replaceState(null, '', cleanUrl);
      console.info('[WP-DEBUG] 已清除,新網址:', cleanUrl);
    }
  })();
  </script>
  <?php
});

進階用法:搭配 WordPress 的條件判斷,只在必要頁面執行

如果你的網站流量很大,想要更精準控制效能,可以加上 is_single() 或 is_singular() 這類 WordPress 條件標籤,讓腳本只在部落格文章或特定自訂內容類型中載入。另外也可以把整個邏輯包成一個獨立 JS 檔,用 wp_enqueue_script 掛載,這樣就能利用 WordPress 原生的相依性管理與版本控制。

無論選哪種做法,重點是保持「不干擾任何追蹤碼」的原則。如果你同時使用 Google Tag Manager,請放心,這段清理程式是在頁面完全載入後才執行,GTM 的 Page View 事件早已觸發完畢,不會漏掉資料。但如果你在 GTM 內有設定「History Change」觸發條件來追蹤虛擬頁面瀏覽,記得測試一下觸發順序,確保不會因為 replaceState 觸發第二次無意義的 pageview。

踩坑提醒與實務開發建議

一、不要一刀砍掉所有 v 參數,只處理 Facebook 特徵型

網路上有些快速解法直接用 url.searchParams.delete('v') 刪除任何 v 參數,這很危險。許多第三方服務(例如影片平台、電商系統)也會使用合法的 v 參數來傳遞版本號。我的做法是用正則過濾,只移除長度 8 碼以上、純十六進制的雜湊值,避免誤傷無辜。

二、確認 GA4 或 GTM 的追蹤邏輯是否需要微調

如果你已經在 GTM 中透過「History Change」觸發條件來捕捉單頁應用式的瀏覽,記得檢查 history.replaceState 會不會被誤判成新的頁面瀏覽。一般情況下它不會觸發 popstate 事件,所以很安全,但若你曾經為了某些特殊需求手動監聽過,最好實測一次。

三、快取外掛與 CDN 通常不影響這段前端清理

這段 JS 只在用戶瀏覽器執行,不會被伺服器端快取。但如果你使用像 Cloudflare 的「Auto Minify」或 Rocket Loader,記得測試腳本是否能正常執行,少數狀況下延遲載入可能讓參數清除發生在使用者已經看到舊網址之後,雖然不影響數據,但體驗上會有短暫閃爍。通常將腳本放在 wp_footer 且不依賴外部資源就沒有問題。

四、保留除錯訊息,但記得在上線後關閉或改用條件判斷

開發階段 console.warn 對抓問題很有幫助,能直接看到哪些頁面被成功清理。但正式上線後,建議用一個簡單的判斷式(例如只在 WP_DEBUG 為 true 時輸出),或是乾脆移除所有 console 訊息,以免被客戶或終端使用者看到不必要的警示。

這樣處理之後,你的 GA 報表就能還原出單一、乾淨的頁面網址,不再被 Facebook 廣告的自動版本碼切碎。數據解讀回到正軌,廣告成效與內容分析終於能對得上。

文章分享