Add Analytics

自动为项目添加 Google Analytics 4 跟踪代码,支持多种框架。

已扫描
适合谁
前端开发人员、网站运营者
不适合谁
无前端项目经验的用户、无需数据分析的静态页面维护者
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @jeftekhari/add-analytics

Skill 说明

命令、参数、文件名以原文为准

Google Analytics 4 设置技能

您正在为项目设置 Google Analytics 4 (GA4)。请遵循此完整指南,正确添加分析功能。

参数

$ARGUMENTS 中解析以下内容:

  • 测量 ID:格式为 G-XXXXXXXXXX(必填,若未提供则询问)
  • --events:包含自定义事件追踪辅助工具
  • --consent:包含 Cookie 同意集成
  • --debug:启用开发模式的调试功能

第一步:检测项目类型

扫描项目以确定框架/配置类型:

优先检测顺序:
1. next.config.js/ts → Next.js
2. nuxt.config.js/ts → Nuxt.js
3. astro.config.mjs → Astro
4. svelte.config.js → SvelteKit
5. remix.config.js → Remix
6. gatsby-config.js → Gatsby
7. vite.config.js + src/App.vue → Vue + Vite
8. vite.config.js + src/App.tsx → React + Vite
9. angular.json → Angular
10. package.json 包含 "react-scripts" → Create React App
11. 仅存在 index.html → 原生 HTML
12. _app.tsx/jsx → Next.js(App Router 检查:app/ 目录)

同时检查:

  • 是否使用 TypeScript(存在 tsconfig.json)
  • 是否已存在分析代码(搜索 gtag、GA、analytics)
  • 使用的包管理器(pnpm-lock.yaml、yarn.lock、package-lock.json)

第二步:验证测量 ID

测量 ID 必须满足以下条件:

  • G- 开头(GA4 格式)
  • 后接恰好 10 个字母数字字符
  • 示例:G-ABC1234567

如果用户提供了 UA- 格式的 ID,请告知:

“您提供的为 Universal Analytics ID(UA-)。GA4 使用以 'G-' 开头的测量 ID。

Universal Analytics 已于 2024 年 7 月停止服务。您需要在 analytics.google.com 创建一个新的 GA4 属性”

第三步:按框架实现

Next.js(App Router - app/ 目录)

创建 app/layout.tsx 修改或新建 components/GoogleAnalytics.tsx

// components/GoogleAnalytics.tsx
'use client'

import Script from 'next/script'

interface GoogleAnalyticsProps {
  measurementId: string
}

export function GoogleAnalytics({ measurementId }: GoogleAnalyticsProps) {
  return (
    <>
      <Script
        src={`https://www.googletagmanager.com/gtag/js?id=${measurementId}`}
        strategy="afterInteractive"
      />
      <Script id="google-analytics" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${measurementId}');
        `}
      </Script>
    </>
  )
}

在根布局中添加:

// app/layout.tsx
import { GoogleAnalytics } from '@/components/GoogleAnalytics'

// 添加到 <body> 或 <html> 内部:
<GoogleAnalytics measurementId="G-XXXXXXXXXX" />

Next.js(Pages Router - pages/ 目录)

修改 pages/_app.tsx

// pages/_app.tsx
import type { AppProps } from 'next/app'
import Script from 'next/script'

const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Script
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
        strategy="afterInteractive"
      />
      <Script id="google-analytics" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${GA_MEASUREMENT_ID}');
        `}
      </Script>
      <Component {...pageProps} />
    </>
  )
}

React(Vite/CRA)

创建 src/lib/analytics.ts

// src/lib/analytics.ts
export const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID

declare global {
  interface Window {
    gtag: (...args: unknown[]) => void
    dataLayer: unknown[]
  }
}

export const initGA = () => {
  if (typeof window === 'undefined') return

  const script = document.createElement('script')
  script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
  script.async = true
  document.head.appendChild(script)

  window.dataLayer = window.dataLayer || []
  window.gtag = function gtag() {
    window.dataLayer.push(arguments)
  }
  window.gtag('js', new Date())
  window.gtag('config', GA_MEASUREMENT_ID)
}

export const pageview = (url: string) => {
  window.gtag('config', GA_MEASUREMENT_ID, {
    page_path: url,
  })
}

export const event = (action: string, params?: Record<string, unknown>) => {
  window.gtag('event', action, params)
}

src/main.tsx 中初始化:

import { initGA } from './lib/analytics'

// 在渲染前初始化
if (import.meta.env.PROD) {
  initGA()
}

Vue 3(Vite)

创建 src/plugins/analytics.ts

// src/plugins/analytics.ts
import type { App } from 'vue'
import type { Router } from 'vue-router'

const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID

declare global {
  interface Window {
    gtag: (...args: unknown[]) => void
    dataLayer: unknown[]
  }
}

export const analyticsPlugin = {
  install(app: App, { router }: { router: Router }) {
    // 加载 gtag 脚本
    const script = document.createElement('script')
    script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
    script.async = true
    document.head.appendChild(script)

    window.dataLayer = window.dataLayer || []
    window.gtag = function gtag() {
      window.dataLayer.push(arguments)
    }
    window.gtag('js', new Date())
    window.gtag('config', GA_MEASUREMENT_ID)

    // 路由变化时追踪
    router.afterEach((to) => {
      window.gtag('config', GA_MEASUREMENT_ID, {
        page_path: to.fullPath,
      })
    })

    // 提供全局方法
    app.config.globalProperties.$gtag = window.gtag
  }
}

Nuxt 3

创建 plugins/analytics.client.ts

markdown

添加分析功能

Nuxt 3

创建 plugins/analytics.client.ts

// plugins/analytics.client.ts
export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig()
  const measurementId = config.public.gaMeasurementId

  if (!measurementId) return

  // 加载 gtag
  useHead({
    script: [
      {
        src: `https://www.googletagmanager.com/gtag/js?id=${measurementId}`,
        async: true,
      },
      {
        innerHTML: `
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${measurementId}');
        `,
      },
    ],
  })

  // 跟踪路由变化
  const router = useRouter()
  router.afterEach((to) => {
    window.gtag('config', measurementId, {
      page_path: to.fullPath,
    })
  })
})

nuxt.config.ts 中添加配置:

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      gaMeasurementId: process.env.NUXT_PUBLIC_GA_MEASUREMENT_ID,
    },
  },
})

Astro

创建 src/components/Analytics.astro

---
// src/components/Analytics.astro
interface Props {
  measurementId: string
}

const { measurementId } = Astro.props
---

<script
  is:inline
  define:vars={{ measurementId }}
  src={`https://www.googletagmanager.com/gtag/js?id=${measurementId}`}
></script>

<script is:inline define:vars={{ measurementId }}>
  window.dataLayer = window.dataLayer || [];
  function gtag() {
    dataLayer.push(arguments);
  }
  gtag('js', new Date());
  gtag('config', measurementId);
</script>

在布局中引入:

---
import Analytics from '../components/Analytics.astro'
---
<html>
  <head>
    <Analytics measurementId="G-XXXXXXXXXX" />
  </head>
</html>

SvelteKit

创建 src/lib/analytics.tssrc/routes/+layout.svelte

// src/lib/analytics.ts
import { browser } from '$app/environment'

export const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID

export function initGA() {
  if (!browser) return

  const script = document.createElement('script')
  script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`
  script.async = true
  document.head.appendChild(script)

  window.dataLayer = window.dataLayer || []
  window.gtag = function gtag() {
    window.dataLayer.push(arguments)
  }
  window.gtag('js', new Date())
  window.gtag('config', GA_MEASUREMENT_ID)
}

export function trackPageview(url: string) {
  if (!browser) return
  window.gtag('config', GA_MEASUREMENT_ID, { page_path: url })
}
<!-- src/routes/+layout.svelte -->
<script lang="ts">
  import { onMount } from 'svelte'
  import { page } from '$app/stores'
  import { initGA, trackPageview } from '$lib/analytics'

  onMount(() => {
    initGA()
  })

  $: if ($page.url.pathname) {
    trackPageview($page.url.pathname)
  }
</script>

<slot />

原生 HTML

将以下代码添加到 <head> 中:

<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>

第四步:环境变量配置

创建或更新 .env.env.local 文件:

# 适用于 Next.js
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX

# 适用于 Vite(React/Vue/Svelte)
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX

# 适用于 Nuxt
NUXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX

如果存在 .env.example,请添加(不包含实际 ID):

# Google Analytics 4 测量 ID
NEXT_PUBLIC_GA_MEASUREMENT_ID=G-XXXXXXXXXX

重要提示:确保已将 .env.local 添加到 .gitignore 文件中。

第五步:事件追踪工具(如使用 --events 标志)

创建一个完整的事件追踪工具集:

# Analytics 功能

## 事件追踪工具(GA4)

推荐事件参考:https://support.google.com/analytics/answer/9267735

type GTagEvent = {

action: string

category?: string

label?: string

value?: number

[key: string]: unknown

}

### 核心事件函数

export const trackEvent = ({ action, category, label, value, ...rest }: GTagEvent) => {

if (typeof window === 'undefined' || !window.gtag) return

window.gtag('event', action, {

event_category: category,

event_label: label,

value,

...rest,

})

}

### 互动事件

export const trackClick = (elementName: string, location?: string) => {

trackEvent({

action: 'click',

category: 'engagement',

label: elementName,

click_location: location,

})

}

export const trackScroll = (percentage: number) => {

trackEvent({

action: 'scroll',

category: 'engagement',

value: percentage,

})

}

### 转化事件

export const trackSignUp = (method: string) => {

trackEvent({

action: 'sign_up',

method,

})

}

export const trackLogin = (method: string) => {

trackEvent({

action: 'login',

method,

})

}

export const trackPurchase = (params: {

transactionId: string

value: number

currency: string

items?: Array<{

itemId: string

itemName: string

price: number

quantity: number

}>

}) => {

trackEvent({

action: 'purchase',

transaction_id: params.transactionId,

value: params.value,

currency: params.currency,

items: params.items,

})

}

### 内容事件

export const trackSearch = (searchTerm: string) => {

trackEvent({

action: 'search',

search_term: searchTerm,

})

}

export const trackShare = (method: string, contentType: string, itemId: string) => {

trackEvent({

action: 'share',

method,

content_type: contentType,

item_id: itemId,

})

}

### 表单事件

export const trackFormStart = (formName: string) => {

trackEvent({

action: 'form_start',

form_name: formName,

})

}

export const trackFormSubmit = (formName: string, success: boolean) => {

trackEvent({

action: 'form_submit',

form_name: formName,

success,

})

}

### 错误追踪

export const trackError = (errorMessage: string, errorLocation?: string) => {

trackEvent({

action: 'exception',

description: errorMessage,

fatal: false,

error_location: errorLocation,

})

}

### 自定义事件构建器(灵活扩展)

export const createCustomEvent = (eventName: string) => {

return (params?: Record<string, unknown>) => {

trackEvent({

action: eventName,

...params,

})

}

}

## 第六步:Cookie 同意集成(若启用 `--consent` 标志)

创建具备同意状态感知的封装层:

type ConsentState = 'granted' | 'denied'

interface ConsentConfig {

analytics_storage: ConsentState

ad_storage: ConsentState

ad_user_data: ConsentState

ad_personalization: ConsentState

}

const CONSENT_COOKIE = 'analytics_consent'

// 初始化同意模式

export const initWithConsent = (measurementId: string) => {

if (typeof window === 'undefined') return

// 设置默认同意状态(用户未同意前为拒绝)

window.gtag('consent', 'default', {

analytics_storage: 'denied',

ad_storage: 'denied',

ad_user_data: 'denied',

ad_personalization: 'denied',

wait_for_update: 500, // 等待同意弹窗加载完成

})

// 加载 gtag 脚本

const script = document.createElement('script')

script.src = https://www.googletagmanager.com/gtag/js?id=${measurementId}

script.async = true

document.head.appendChild(script)

window.dataLayer = window.dataLayer || []

window.gtag = function gtag() {

window.dataLayer.push(arguments)

}

window.gtag('js', new Date())

window.gtag('config', measurementId)

// 检查已保存的同意状态

const savedConsent = getCookie(CONSENT_COOKIE)

if (savedConsent) {

updateConsent(JSON.parse(savedConsent))

}

}

// 更新用户同意选择

export const updateConsent = (consent: Partial<ConsentConfig>) => {

if (typeof window === 'undefined' || !window.gtag) return

const consentState: ConsentConfig = {

analytics_storage: consent.analytics_storage || 'denied',

ad_storage: consent.ad_storage || 'denied',

ad_user_data: consent.ad_user_data || 'denied',

ad_personalization: consent.ad_personalization || 'denied',

}

window.gtag('consent', 'update', consentState)

// 保存至 Cookie

setCookie(CONSENT_COOKIE, JSON.stringify(consentState), 365)

}

// 快捷操作函数

export const acceptAll = () => {

updateConsent({

analytics_storage: 'granted',

ad_storage: 'granted',

ad_user_data: 'granted',

ad_personalization: 'granted',

})

}

export const acceptAnalyticsOnly = () => {

updateConsent({

analytics_storage: 'granted',

ad_storage: 'denied',

ad_user_data: 'denied',

ad_personalization: 'denied',

})

}

export const denyAll = () => {

updateConsent({

analytics_storage: 'denied',

ad_storage: 'denied',

ad_user_data: 'denied',

ad_personalization: 'denied',

})

}

// Cookie 工具函数

function setCookie(name: string, value: string, days: number) {

const date = new Date()

date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000)

document.cookie = ${name}=${value};expires=${date.toUTCString()};path=/;SameSite=Lax

}

function getCookie(name: string): string | null {

const match = document.cookie.match(new RegExp((^| )${name}=([^;]+)))

return match ? match[2] : null

}

## 第七步:调试模式(若启用 `--debug` 标志)

在开发环境中启用调试模式:

// 开发环境启用调试模式

if (process.env.NODE_ENV === 'development') {

window.gtag('config', 'G-XXXXXXXXXX', {

debug_mode: true,

})

}

建议安装 Chrome 浏览器插件 [Google Analytics Debugger](https://chrome.google.com/webstore/detail/google-analytics-debugger/jnkmfdileelhofjcijamephohjechhna) 以辅助调试。

## 步骤 8:TypeScript 类型声明

如果使用 TypeScript,请创建 `types/gtag.d.ts` 文件:

// types/gtag.d.ts

declare global {

interface Window {

gtag: Gtag.Gtag

dataLayer: object[]

}

}

declare namespace Gtag {

interface Gtag {

(command: 'config', targetId: string, config?: ConfigParams): void

(command: 'set', targetId: string, config: ConfigParams): void

(command: 'set', config: ConfigParams): void

(command: 'js', date: Date): void

(command: 'event', eventName: string, eventParams?: EventParams): void

(command: 'consent', consentArg: 'default' | 'update', consentParams: ConsentParams): void

(...args: unknown[]): void

}

interface ConfigParams {

page_title?: string

page_location?: string

page_path?: string

send_page_view?: boolean

debug_mode?: boolean

[key: string]: unknown

}

interface EventParams {

event_category?: string

event_label?: string

value?: number

[key: string]: unknown

}

interface ConsentParams {

analytics_storage?: 'granted' | 'denied'

ad_storage?: 'granted' | 'denied'

ad_user_data?: 'granted' | 'denied'

ad_personalization?: 'granted' | 'denied'

wait_for_update?: number

}

}

export {}

## 步骤 9:验证检查清单

完成实现后,请进行以下验证:

1. [ ] 测量 ID 格式正确(G-XXXXXXXXXX)
2. [ ] 生产环境脚本已加载(检查网络标签页)
3. [ ] GA4 仪表板中的实时报告显示活动数据
4. [ ] 页面浏览在导航时被正常追踪
5. [ ] 控制台无与 gtag 相关的错误
6. [ ] 环境变量未提交到 Git
7. [ ] TypeScript 无类型错误(如适用)

## 步骤 10:总结输出

完成设置后,请向用户提供以下信息:

1. **创建或修改的文件**(列出文件名)
2. **所需的环境变量**(附示例值)
3. **下一步操作**:
   - 将测量 ID 添加至环境变量
   - 部署并验证 GA4 实时报告中的数据
   - 在 GA4 仪表板中设置转化事件
   - 考虑为关键用户行为添加自定义事件

## 常见问题与解决方案

**“gtag 未定义”**
- 脚本尚未加载;请确保异步加载逻辑正确处理

**GA4 中无数据**
- 检查广告拦截器是否阻止了跟踪
- 确认测量 ID 是否正确
- 查看浏览器控制台是否存在错误

**页面浏览重复计数**
- 单页应用路由触发重复事件;需实现去重机制

**GDPR 合规性**
- 对欧盟用户必须启用同意模式
- 使用 --consent 标志添加同意管理功能
J
@jeftekhari

已收录 1 个 Skill

相关推荐