gatsby-plugin-google-gtag:在 Gatsby 站点中集成 Google Global Site Tag 的完整实践
【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
本篇以 Gatsby 仓库中的 gatsby-plugin-google-gtag 插件文档 为核心,完整覆盖该插件的安装、配置参数(trackingIds、gtagConfig、pluginConfig)、自定义事件与<OutboundLink>组件的使用方式,并结合仓库源码剖析其在 SSR 阶段注入追踪脚本、在浏览器端发送page_view事件的具体实现链路,帮助你在 Gatsby 5 站点中正确接入 GA4 / Google Ads 等 Google 标签体系。
什么是 Global Site Tag(gtag.js)
Google 的 global site tag(gtag.js)是一个 JavaScript 标签框架与 API,允许你将事件数据发送到 Google Analytics、Google Ads、Campaign Manager、Display & Video 360 以及 Search Ads 360。它的设计目标是合并多个 Google 标签系统,因此可以取代较旧的 analytics.js(对应 Gatsby 生态中的gatsby-plugin-google-analytics插件)。
gatsby-plugin-google-gtag的定位就是在 Gatsby 站点中方便地注入 gtag.js。相比手动复制粘贴 Google 给出的代码片段,该插件额外解决了 SPA 场景下的几个关键问题:
- 在每次 Gatsby 路由变化时自动发送
pageview事件(传统<script>标签只会在首次加载时发一次); - 通过
exclude选项按 glob 表达式排除某些路径; - 通过
respectDNT选项尊重浏览器的 "Do Not Track" 设置; - 通过
<OutboundLink>组件便捷地追踪出站链接点击。
重要前提:该插件仅在 production 模式下工作。要验证 Global Site Tag 是否正确安装并触发事件,需要运行gatsby build && gatsby serve。这一点在源码中得到直接印证——gatsby-ssr.js 的onRenderBody开头即有守卫:
if (process.env.NODE_ENV !== `production` && process.env.NODE_ENV !== `test`) return null即非 production(且非测试)环境下,插件在渲染阶段直接不做任何注入。
安装
npm install gatsby-plugin-google-gtag插件的 package.json 中声明了对gatsby ^5.0.0的 peer 依赖,运行环境要求 Node>=18.0.0 <26。
基本配置
trackingIds是必填选项,缺失时插件无法正常工作。完整的配置示例如下:
module.exports = { plugins: [ { resolve: `gatsby-plugin-google-gtag`, options: { // You can add multiple tracking ids and a pageview event will be fired for all of them. trackingIds: [ "GA-TRACKING_ID", // Google Analytics / GA "AW-CONVERSION_ID", // Google Ads / Adwords / AW "DC-FLOODIGHT_ID", // Marketing Platform advertising products (Display & Video 360, Search Ads 360, and Campaign Manager) ], // This object gets passed directly to the gtag config command // This config will be shared across all trackingIds gtagConfig: { optimize_id: "OPT_CONTAINER_ID", anonymize_ip: true, cookie_expires: 0, }, // This object is used for configuration specific to this plugin's specific configuration pluginConfig: { // Puts tracking script in the head instead of the body head: false, // Setting this parameter is also optional respectDNT: true, // Avoids sending pageview hits from custom paths exclude: ["/preview/**", "/do-not-track/me/too/"], // Defaults to https://www.googletagmanager.com origin: "YOUR_SELF_HOSTED_ORIGIN", // Delays processing pageview events on route update (in milliseconds) delayOnRouteUpdate: 0, }, }, }, ], }选项的合法性由 gatsby-node.js 中导出的pluginOptionsSchema通过 Joi 在插件加载时校验,默认值与约束如下(源码中的定义):
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
trackingIds | string[] | 无(required) | 追踪 ID 列表,没有它们不会生成追踪代码 |
gtagConfig | object | {} | 直接透传给gtag('config', ...)命令 |
gtagConfig.anonymize_ip | boolean | false | 启用 IP 匿名化(_anonymizeIP) |
pluginConfig.head | boolean | false | 将追踪脚本放入<head>而非<body> |
pluginConfig.respectDNT | boolean | false | 对开启 "Do Not Track" 的访客完全不加载 gtag |
pluginConfig.exclude | string[] | [] | 以 glob 表达式排除的路径 |
pluginConfig.origin | string | https://www.googletagmanager.com | 自托管脚本的 origin |
pluginConfig.delayOnRouteUpdate | number | 0 | 路由更新后处理 pageview 事件的延迟(毫秒) |
仓库中的 schema 测试 明确验证了错误配置会产生的报错信息,例如缺失trackingIds时报"trackingIds" is required、pluginConfig.origin传数字时报"pluginConfig.origin" must be a string等。gtagConfig使用了unknown(true),因此除了显式声明的optimize_id与anonymize_ip,其余键都会原样透传。
选项详解
gtagConfig.anonymize_ip
某些国家(例如德国)要求对 Google Site Tag 使用_anonymizeIP函数,否则不允许使用。开启该选项后,插件会注入如下代码块(对应 gatsby-ssr.js 中的内联脚本生成逻辑):
function gaOptout() { ;(document.cookie = disableStr + "=true; expires=Thu, 31 Dec 2099 23:59:59 UTC;path=/"), (window[disableStr] = !0) } var gaProperty = "UA-XXXXXXXX-X", disableStr = "ga-disable-" + gaProperty document.cookie.indexOf(disableStr + "=true") > -1 && (window[disableStr] = !0)从源码看,gaProperty取的是trackingIds数组中的第一个ID,ga-disable-<ID>cookie 会被检查并在页面加载时同步到window标志位。
如果希望访客能够主动设置 Opt-Out-Cookie(即不再被追踪),可以在站点页脚/法律声明等位置放置一个链接:
<a href="javascript:gaOptout();">Deactivate Google Tracking</a>gtagConfig.optimize_id
如果需要使用 Google Optimize 做 A/B 测试,可以添加这个可选的 Optimize 容器 ID,以便 Google Optimize 为你的站点加载正确的测试参数。
其他gtagConfig选项
gtagConfig会原样传入gtag 的 config 命令,因此它支持的一切字段都可以使用,例如gtagConfig.cookie_name、gtagConfig.sample_rate。如果你正在从 analytics.js 插件迁移过来,意味着所有 Create Only Fields 都应改为 snake_case 命名(如cookieName→cookie_name)。
pluginConfig.respectDNT
启用该可选项后,开启了 "Do Not Track" 的访客将完全不会加载 Google Global Site Tag。虽然使用 Global Site Tag 不一定构成法律意义上的 "追踪",但为更重视隐私的用户群体服务时,这是一个有价值的开关。
从实现看,gatsby-ssr.js 会在整个dataLayer/gtag初始化代码外层包裹一个条件判断:
if(!(navigator.doNotTrack == "1" || window.doNotTrack == "1")) { window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); // ... gtag('config', ...) 对每个 trackingId 执行 }当respectDNT为false(默认)时,该条件渲染为if(true),即不做任何 DNT 检查。对应的测试用例 分别断言了默认情况下输出 HTML 中不含 DNT 字符串、开启后包含该字符串。
pluginConfig.exclude
如果需要将某些路径排除在追踪体系之外,可以把一个或多个路径以glob 表达式的形式加入该可选数组,例如["/preview/**", "/do-not-track/me/too/"]。
底层实现分两步:
- SSR 阶段(gatsby-ssr.js):使用
minimatch(插件的运行时依赖之一)将每个 glob 转换为正则,并写入页面内联脚本:window.excludeGtagPaths=[/^\S*.../, ...]; - 浏览器阶段(gatsby-browser.js):路由更新时逐一用这些正则测试
location.pathname,命中任一正则则跳过本次page_view事件。
pluginConfig.origin
默认脚本来源为https://www.googletagmanager.com。如果你自托管了 gtag 脚本,可以替换为自有 origin。从 SSR 源码 可以看到,origin同时作用于两处:
<head>中注入的<link rel="preconnect">与<link rel="dns-prefetch">(Lighthouse 建议对 Google Tag Manager 域名做预连接,以降低脚本加载延迟);- 实际
<script async src="${origin}/gtag/js?id=${firstTrackingId}">的src。
相关测试 验证了默认 origin 与自定义 origin 两种情况下上述三处均使用同一 origin。
pluginConfig.delayOnRouteUpdate
如果需要延迟处理路由更新时的 pageview 事件(例如等待gatsby-plugin-transition-link的页面过渡动画完成),该选项会在生成 pageview 事件之前加入指定的毫秒级延迟。
插件在 Gatsby 生命周期中的工作方式
SSR 阶段:onRenderBody注入脚本
gatsby-ssr.js 导出的onRenderBody是插件的核心。它做了以下几件事:
- preconnect / dns-prefetch:为 origin 域注入
<head>链接,优化脚本加载性能; - 关闭 gtag 内置的初始 pageview:在透传的
gtagConfig中强制设置gtagConfig.send_page_view = false(L25)。这是为了避免首次加载时由config命令触发一次、而 SPA 路由又由浏览器端再发一次,从而造成重复的 pageview 事件; - 按
head选项决定脚本位置:pluginConfig.head为真时通过setHeadComponents注入<head>,否则通过setPostBodyComponents注入到<body>之后(L40-L42); - 生成内联配置脚本:对每个
trackingId逐条生成gtag('config', '<id>', {...})命令,gtagConfig经JSON.stringify序列化后内嵌。
最终产出的 HTML 结构等价于:
<script async src="https://www.googletagmanager.com/gtag/js?id=GA-TRACKING_ID"></script> <script> window.excludeGtagPaths=[/* 由 exclude 生成的正则 */]; /* 若 anonymize_ip: true,此处还有 gaOptout 代码块 */ if(true /* respectDNT 为 true 时替换为 DNT 判断 */) { window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'GA-TRACKING_ID', {"send_page_view":false, ...}); gtag('config', 'AW-CONVERSION_ID', {"send_page_view":false, ...}); } </script>浏览器阶段:onRouteUpdate发送 pageview
gatsby-browser.js 监听 Gatsby 的onRouteUpdateAPI:
exports.onRouteUpdate = ({ location }, pluginOptions = {}) => { if (process.env.NODE_ENV !== `production` || typeof gtag !== `function`) { return null } // ... 排除路径检查 const sendPageView = () => { const pagePath = location ? location.pathname + location.search + location.hash : undefined window.gtag(`event`, `page_view`, { page_path: pagePath }) } // 双层 requestAnimationFrame + setTimeout(delayOnRouteUpdate) }几个值得注意的实现细节:
- 事件携带完整的
page_path(pathname + search + hash),保证带 query/锚点的导航也被正确记录; - 发送前会用
window.excludeGtagPaths正则测试当前pathname,命中即返回; sendPageView被包裹在两层requestAnimationFrame之后再叠加setTimeout(delayOnRouteUpdate)——源码注释说明这是为了确保react-helmet等对 document 的修改已经完成;在不支持requestAnimationFrame的环境下退化为固定的 32ms 延迟(模拟两次 rAF)再加配置延迟。
自定义事件(Custom Events)
该插件会自动为所有trackingIds中给出的产品在每次 Gatsby 路由变化时发送pageview事件。如需触发自定义事件,可以直接访问全局的window.gtag,向所有产品发送:
window.gtag("event", "click", { ...data })或者用send_to指定特定产品:
window.gtag("event", "click", { send_to: "AW-CONVERSION_ID", ...data })无论哪种方式,都要记得对 SSR 做防护:
typeof window !== "undefined" && window.gtag("event", "click", { ...data })<OutboundLink>组件
为了简化出站链接点击的追踪,插件提供了一个<OutboundLink>组件(实现见 src/index.js,类型定义见 index.d.ts),用法与<a>元素一致:
import React from "react" import { OutboundLink } from "gatsby-plugin-google-gtag" export default () => ( <div> <OutboundLink href="https://www.gatsbyjs.com/plugins/gatsby-plugin-google-gtag/"> Visit the Google Global Site Tag plugin page! </OutboundLink> </div> )从源码实现看,它比文档描述做了更多细节处理:
- 先调用用户传入的
onClick(如果提供),随后发送event_category: "outbound"、event_label: props.href的click事件; - 重定向判定:只有左键单击、且未附带
altKey/ctrlKey/metaKey/shiftKey、defaultPrevented未设置、target为_self(或未指定)时才会由组件接管跳转;中键点击、target="_blank"等场景直接放行,不发送 beacon、不阻止默认行为; - 可接管跳转的场景下使用
transport_type: "beacon",并通过event_callback在事件上报完成后才执行document.location = href,尽量降低跳转导致事件丢失的概率;若当前环境没有window.gtag(如未通过校验或 DNT 被排除),则退化为直接跳转。
组件以React.forwardRef实现并透传全部<a>属性,因此className、aria-*等属性均可正常使用。
验证与排错
由于插件仅在 production 模式生效,推荐的验证流程是:
gatsby build && gatsby serve然后在浏览器中打开页面,通过 Google 官方的 Tag Assistant 或 GA4 的 DebugView 确认事件是否上报。如果事件没有触发,可以按以下顺序排查:
trackingIds是否已配置且格式正确(Joi schema 缺失必填项会在构建时直接报错);- 是否误在
gatsby develop下测试(开发模式下 SSR 注入与浏览器端onRouteUpdate均被守卫短路); - 当前路径是否命中
pluginConfig.exclude的 glob 表达式,或开启了respectDNT而浏览器启用了 DNT; - 自托管
origin是否可正常访问/gtag/js路径。
小结
gatsby-plugin-google-gtag通过三个 Gatsby API 协作完成完整链路:gatsby-ssr.js 在onRenderBody中注入 preconnect、gtag 加载脚本与逐 ID 的 config 命令(并强制send_page_view: false防止首次加载重复计数),gatsby-browser.js 在onRouteUpdate中处理排除路径、延迟与 rAF 时序后发送page_view,gatsby-node.js 用 Joi schema 保证选项合法且提供合理默认值,而 src/index.js 提供了带跳转时序优化的<OutboundLink>组件。配合本文完整的参数说明与源码级解释,你可以放心地将 GA4、Google Ads(AW-)及 Marketing Platform(DC-)等产品接入自己的 Gatsby 站点。
【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考