如何通过Google Tag Manager为Next-Js设置Google Analytics?

27

之前我在我的next js应用中使用react-ga npm模块来插入Google Analytics。它只是这样的:

import ReactGA from 'react-ga'

export const initGA = () => {
  ReactGA.initialize('UA-*******-*', {
    titleCase: false
  })
}

export const logPageView = () => {
  if (window.location.href.split('?')[1]) {
    ReactGA.set({page: window.location.pathname + '?' + window.location.href.split('?')[1]})
    ReactGA.pageview(window.location.pathname + '?' + window.location.href.split('?')[1])
  } else {
    ReactGA.set({page: window.location.pathname})
    ReactGA.pageview(window.location.pathname)
  }
}

然后我在我的应用程序的每个页面插入的头部中调用了logPageView函数,代码如下:

```javascript logPageView(); ```
  componentDidMount () {
    if (!window.GA_INITIALIZED) {
      initGA()
      window.GA_INITIALIZED = true
    }
    logPageView()
  }
  componentWillReceiveProps () {
    if (!window.GA_INITIALIZED) {
      initGA()
      window.GA_INITIALIZED = true
    }
    logPageView()
  }

现在我想使用Google Tag Manager来处理分析页面查看。我该怎么做?

10个回答

46
为了使用Google Tag Manager,您应该在每个页面上注入标签管理器脚本。由于_document.js是每个页面的包装器,您应该像这样将GTM脚本添加到部分中的_document.js中:
<Head>
  <script dangerouslySetInnerHTML={{
    __html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
  })(window,document,'script','dataLayer','GTM-*****');`,
  }}>
  </script>
  ...
</Head>

现在,您已经准备好在您的Next.js应用程序中使用Google Tag Manager了。您应该只从GTM仪表板处理页面查看和其他与分析相关的内容。

要为单页面应用程序(如Next.js)设置Google Analytics页面查看,您可以按照这些步骤进行操作。


"dangerouslySetInnerHTML" 看起来很危险!它可能会让你面临跨站脚本攻击(XSS)。 - Muhammad Riyaz
3
只要你确定脚本是安全的,那么它并不危险,而在这种情况下它是安全的。 - Black
4
如果有人成功操纵dangerouslySetInnerHTML中的任何内容,那么你面临的问题比谷歌分析更加严重。 - Isaac Pak
你也可以在那段文本中添加 .replace(/\n\s*/g, "") 来删除换行符。 - Lucas Vazquez

28

不需要任何特殊的库,一些回答看起来不完整。只需将脚本添加到<Head>,而noscript添加到<body>中的_document.js即可。

import Head from 'next/document'  

<Head>
  <script dangerouslySetInnerHTML={{__html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
          })(window,document,'script','dataLayer','GTM-XXXXXX');`}} />
</Head>
    
<body style={{ margin: 0 }}>
   <noscript dangerouslySetInnerHTML={{ __html: `<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
        height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
      }}
    />
    <Main />
    <NextScript />
</body>

3
您可能希望从next/document中导入Head组件,而不是next/head。即:import { Head } from 'next/document'。根据Next.js 文档,它们是不同的,对于适用于所有页面的代码,应优先使用来自next/document的组件。 - Chuck
这应该是被接受的答案,因为它将允许nextjs在HTML中返回代码。react-gtm-module将使用JavaScript在运行时注入它,因此它将无法按预期工作。 - Ahmad Alfy

16

由于您正在使用nextJS,因此无需添加来自Google Analytics的纯JavaScript,您所需要的只是GA跟踪ID。

然后您可以创建util功能:

export const event = ({ action, category, label, value }) => {
  window.gtag('event', action, {
    event_category: category,
    event_label: label,
    value: value
  })
}

将以下内容添加到您的_document.js文件中:

<script
  dangerouslySetInnerHTML={{
  __html: `
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '${GA_TRACKING_ID}');
`}}
/>

之后,您只需要在页面/组件中导入util函数并调用:

gtag.event({
  action: 'submit_form',
  category: 'Contact',
  label: this.state.message
})

参考资料: NextJS中使用谷歌分析的示例


1
谢谢。这是一个很好的替代方案。 - Soorena

12

我找到了一种更好的实现方式。我们可以使用react-gtm-module库来完成。

正如Ryan Elainska在他们的博客中提到的,在我的NextJS安装的_app.js文件中,可以使用在Next.js中使用Google Tag Manager

import App, { Container } from 'next/app'
import React from 'react'
import './app.css'
import TagManager from 'react-gtm'

const tagManagerArgs = {
  id: 'GTM-XXXXXXX'
}

class MyApp extends App {
  componentDidMount () {
    TagManager.initialize(tagManagerArgs)
  }

  render () {
    const { Component, pageProps } = this.props
    return (
      <Container>
        <Component {...pageProps} />
      </Container>
    )
  }
}

export default MyApp

感谢提供_app.js的解决方案。至于代码,'react-gtm'应该改为'react-gtm-module'。在这里转载的原始博客中是错误的。 - stahlmanDesign
1
tagManagerArgs = { id: 'GTM-XXXXXXX' } 应更改为 tagManagerArgs = { gtmId: 'GTM-XXXXXXX' } - stahlmanDesign
这个库对我来说不起作用,它总是返回404。 - shontauro

5

我正在使用react-gtm-module,并在_app.jscomponentDidMount中进行配置。

 componentDidMount() {
    const tagManagerArgs = {
      gtmId = 'GTM-00001'
    }

    TagManager.initialize(tagManagerArgs);
  }

这是我在2020年2月11日更新的解决方案。


3

我正在使用redux在我的next.js应用程序中。

如果您正在使用redux,这是一个相当不错的解决方案:redux-beacon + react-gtm-module

以下是初始化代码。该代码可以通过钩子或_app.js中的componentDidMount触发,或者如果您正在使用redux,则可以通过redux操作触发。

const dataLayer = { ...your dataLayer config... }
const tagManagerArgs = {
  gtmId: process.env.GTM_ID,
  auth: process.env.GTM_AUTH,
  preview: process.env.GTM_PREVIEW,
  dataLayer
}
TagManager.initialize(tagManagerArgs)

下面是使用 eventMap 创建的中间件。
import { EventsMapper, createMiddleware } from 'redux-beacon'
import GoogleTagManager from '@redux-beacon/google-tag-manager'

const gtm = GoogleTagManager()

export const eventsMap: EventsMapper = action => {
  switch (action.type) {
    default:
      return []
  }
}


export const gtmMiddleware = createMiddleware(eventsMap, gtm)

2

从 Next.js v11 开始,建议使用他们的 <Script> 标签,并将其添加到 App 组件 中。

pages/_app.jsx

import React from 'react';
import Script from 'next/script';

const App = ({ Component, pageProps }) => {
  return (
    <>
      <Script id="gtm" strategy="afterInteractive">
        {`
          (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
          new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
          j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
          'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
          })(window,document,'script','dataLayer','GTM-XXXXXXX');
        `}
      </Script>
      <noscript>
        <iframe
          src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
          height="0"
          width="0"
          style={{
            display: 'none',
            visibility: 'hidden',
          }}
        ></iframe>
      </noscript>

      <Component {...pageProps} />
    </>
  );
};

export default App;

你可以在nestjs-starter中看到类似的解决方案,我也从环境变量设置标签来实现gtag。对于v10及以下版本,请按照Google指南使用普通的<script>标签。请记住,Google Analytics会自动跟踪页面,但这并不适用于每种情况。例如,hashsearch参数的更改是无法跟踪的。这可能会导致很多混淆。例如,在使用HashRouter或锚链接时,导航将无法跟踪。为了完全控制页面视图跟踪,您可以禁用自动跟踪。详细解释请参见:React(或其他任何内容)上的Google Analytics(UA&GA4)的终极指南
手动页面跟踪:https://dev59.com/E1sW5IYBdhLWcg3wi36j#63249329

2

我推荐一个名为nextjs-google-analytics的开源库,它在github上有文档,在npm上已发布。它的<GoogleAnalytics/>组件是NextJS的<Script/>的包装器,如其他答案中提到的一样,并具有其他功能,例如trackPageViews属性,可以自动跟踪访问者路由更改。虽然这个库很小,但在我看来使你的代码库更整洁。


1

虽然这篇文章有些旧,但我最近写了关于此问题的内容,并在这里详细介绍了两种解决方案:https://morganfeeney.com/how-to/integrate-google-tag-manager-with-next-js

在 Next.js v11.0.0 之前,最简单的方法是使用自定义 _document。

在自定义 _document 中添加 GTM 脚本,如下所示:https://nextjs.org/docs/advanced-features/custom-document

import Head from 'next/document';
...

<Head>
  <script
    dangerouslySetInnerHTML={{
      __html: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
      })(window,document,'script','dataLayer','GTM-XXXX');`,
    }}
  />
</Head>

<body>
  <Main />
  <NextScript />
  <noscript
    dangerouslySetInnerHTML={{
      __html: `<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX" height="0" width="0" style="display: none; visibility: hidden;" />`,
    }}
  />
</body>

但是如何跟踪页面浏览量??

window.onLoad 在使用客户端路由导航时不会触发,因此即使添加了脚本,它也没有达到您的预期。

我的首选方法是使用这样的函数:

export const gtmVirtualPageView = (rest) => {
  window.dataLayer?.push({
    event: 'VirtualPageView',
    ...rest,
  });
};

在 _app.tsx 文件中添加以下配置:
import '../styles/globals.css';
import { useEffect } from 'react';
import { useRouter } from 'next/router'
import { gtmVirtualPageView } from '../lib/gtm';

function MyApp({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() => {
    const mainDataLayer = {
      pageTypeName: pageProps.page || null,
      url: router.pathname,
    };

    window.onload = () => window.dataLayer?.push({...mainDataLayer});

    gtmVirtualPageView(mainDataLayer);

  }, [pageProps])

  return <Component {...pageProps} />
}

export default MyApp

这样可以通过pageProps将数据传递到数据层。

0
要在您的Next.js应用程序中使用Google Tag Manager,您应该在每个页面上注入您的标签管理器脚本。您可以通过在该项目的页面文件夹中创建_document.js来实现此目的,并且您必须编辑_app.js以使用Google Tag Manager。以下是我的_app.js代码,您可以按照此代码进行操作:
const App = ({ Component, pageProps }) => {
  const router = useRouter()
  useEffect(() => {
    const handleRouteChange = (url) => {
      gtag.pageview(url)
    }
    router.events.on('routeChangeComplete', handleRouteChange)
    router.events.on('hashChangeComplete', handleRouteChange)
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
      router.events.off('hashChangeComplete', handleRouteChange)
    }
  }, [router.events])

  return (
    <>
      {/* Global Site Tag (gtag.js) - Google Analytics */}
      <Script
        strategy="afterInteractive"
        src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
      />
      <Script
        id="gtag-init"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${gtag.GA_TRACKING_ID}', {
              page_path: window.location.pathname,
            });
          `,
        }}
      />
      <Component {...pageProps} />
    </>
  )
}

export default App

这里是_document.js:

export default function Document() {
    return (
        <Html lang='en'>
            <Head>
                {/* Global Site Tag (gtag.js) - Google Analytics */}
                <script
                    dangerouslySetInnerHTML={{
                        __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
          `,
                    }}
                />
            </Head>
            <body>
                <Main />
                <NextScript />
            </body>
        </Html>
    )
}

创建一个gtag.js文件:
export const GA_TRACKING_ID = '**********'

// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
export const pageview = (url) => {
    window.gtag('config', GA_TRACKING_ID, {
        page_path: url,
    })
}

// https://developers.google.com/analytics/devguides/collection/gtagjs/events
export const event = ({ action, category, label, value }) => {
    window.gtag('event', action, {
        event_category: category,
        event_label: label,
        value: value,
    })
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接