LoginSignup
69
42

More than 3 years have passed since last update.

nuxtでGTMタグをheadとbodyに埋め込む(非SPA、モジュール不使用、シンプル)

Last updated at Posted at 2020-03-14

クライアント案件で、GTMタグを埋め込みたいとの連絡をいただいた。

通常の静的サイトであれば、GTM用のタグを
<head>内と<body>直後の全ページに設置するだけで良いのだけれど、
これをnuxtでgenerate出力した場合のサイトにシンプルに適用する方法について共有します。
(20/02/19 時点で動作確認)

対象サイト

  • nuxt.js(v2.0.0)で構築
  • universalモード(非SPA)
  • generateで生成した静的Webサイト(下層ページあり)

やりたいこと

GTMから発行される下記タグを全ページに設置する(あるいはそれと同等のことをする)。

  • <head></head>
*.html
<!-- Google Tag Manager -->
<script>(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>
<!-- End Google Tag Manager -->
  • <body>直後に
*.html
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

いろんなやり方ある・・・が、自社案件じゃないと歯がゆい

公式モジュール

nuxt公式が出しているGoogleTagManager用のモジュールを使ってみる。

ところが情報色々ぐぐってみると、
デフォルトではページビューの計測オプションがfalseになっており、
計測したい場合はこちらのオプション有効化することに加え、
管理画面側でページビューを拾うためのタグの設定などが必要だそう。

先方管理画面のログイン権限がないような今回のケースだと、
担当者にタグの設定を一発で的確に指示できる自信があまりないし、
設定の不備による計測ミスなど状況をややこしくしたくない、、
実装サイドだけで完結させられないか、他の方法を検討。

自前でプラグイン実装

これも公式にのっている方法で、
プラグインファイルを作ってnuxt.config.jsで読み込めばいいよというやつ。

この方法は、nuxtに対して「毎回遷移時にコード送ってね」というコードを書いているので、
(つまるところそれを簡単に使えるようしてくれているのが先程のモジュールなわけで、)
nuxtの内部で処理されるため、<head>とか<body>にコードが出力されるわけではない。
し、どちらにせよイベント送信してゴニョゴニョするってことは
受信側でタグ設定が必要になりそうなので、ナシ。

いやいや、もっとシンプルに・・該当の箇所に埋め込みたいだけなのだ・・🐵
ということで調べて、たどり着きました。

【結論】nuxt.config.js(Vue meta)で記述できる

nuxt.jsのAPI:headを利用し、vue-metaのルールに則って記述するだけで大丈夫でした。

nuxt.config.js に下記を追記しましょう。

nuxt.config.js
const gtmID = 'GTM-XXXXXXX'
const gtmHeadTag = `(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','${gtmID}');`
const gtmBodyTag = `<iframe src="https://www.googletagmanager.com/ns.html?id=${gtmID}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`

export default {
  head: {
    script: [
      {
        hid: 'gtmHead',
        innerHTML: gtmHeadTag
      }
    ],
    noscript: [
      {
        hid: 'gtmBody',
        innerHTML: gtmBodyTag,
        pbody: true
      }
    ],
    __dangerouslyDisableSanitizersByTagID: {
      'gtmHead': ['innerHTML'],
      'gtmBody': ['innerHTML']
    }
  }
}

コンパイル後のソース

*.html
<head>...
<script data-n-head="ssr" data-hid="gtmHead">(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>
...</head>
<body>
  <noscript data-n-head="ssr" data-hid="gtmBody" data-pbody="true"><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
...

解説(補足)

script:[]

<script>タグを<head></head>内に埋め込めます。
共通で読み込みたいsrcファイルなどを指定(公式)する際にも使えますが、
innerHTMLというキーに文字列を渡すと、<script>~<script>内に文字列を挿入できます。

https://vue-meta.nuxtjs.org/api/#script

noscript:[]

<noscript>タグを<body></body>内に埋め込めます。
オプションで、挿入位置を指定できます。
<body>直後の場合はpbody:true</body>直前の場合はbody:trueを指定します。

https://vue-meta.nuxtjs.org/api/#noscript
https://vue-meta.nuxtjs.org/api/#noscript-text

__dangerouslyDisableSanitizersByTagID:

①inject許可

vue.jsで構築されたアプリケーションは、DOM攻撃(XSS等)の危険性があるので、
管理外の<head><body>へのタグの追加・変更に堅いです。
ここで指定されたキーバリューは、例外となりinjectを許可されます。

https://vue-meta.nuxtjs.org/api/#dangerouslydisablesanitizersbytagid

※注:同様に__dangerouslyDisableSanitizersというのがありますが、
こちらは指定したタグ全般に対し例外適用されるので、ID指定のほうを使いましょう。

②escapeされない

また、ここで指定された値はrawData扱いされるため、
htmlに出力される際escapeされないというところもポイントとなります。

https://vue-meta.nuxtjs.org/api/#add-other-raw-data

やってみていただくとわかるのですが、こちらのオプションをつけずに出力した場合、
<body>側に埋め込んだ<iframe>タグは下記のように&lt;iframeと出力されてしまいます。
(これを解決するのに、DOM Parserなども試したが駄目で、ハマりました・・)

*.html
<body>
  <noscript data-n-head="ssr" data-hid="gtmBody" data-pbody="true">&lt;iframe src=&quot;https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;display:none;visibility:hidden&quot;&gt;&lt;/iframe&gt;</noscript>

その他注意

vue-meta公式だとIDに設定するキーの名前がvmidになっているのですが、
nuxtの場合はhidにしてあげないと効きません。(こちらも地味にハマった、、)

おわり

シンプルな実装で、計測も無事確認できたので、同じような状況の方はためしてみてください🎉
(ちなみにこのスクリプト挿入はGTMタグ以外にも応用可能です)

69
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
69
42