GTMはdataLayerの情報をどのように扱っているのか

# 結論
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2998651/45782de1-3883-4e5d-93f4-c571c71d7b58.png)

[参考](https://www.simoahava.com/analytics/google-tag-manager-data-model/)

**data model**という領域をdataLayerとGTMの間に置いて、その領域を介してdataLayerの情報にアクセスしている。
- イメージとしては、dataLayer配列を一つにまとめたもの
- まとめ方としてはdataLayer配列に格納されている全てのkeyそれぞれに対し、格納された最新のvalueのみ残す。
- dataLayerに値がpushされるたびにdata modelが更新される
- アクセス方法：data modelが持つgetメソッドにキー名を渡す
- アクセス出来る情報：data modelの情報のみ


# 前提
GTMはブラウザが持つデータ領域であるdataLayerの値を使ってGA4にデータを送信します。
例えば、以下のようなGA4イベントを作成することを考えます。

タグ名：testクリックタグ
タイプ：GA4イベント
イベント名：test_click
測定ID：GTM-ABCDEFG
トリガータイプ：リンクのみ
イベントパラメータ：
   キー名：クリックテキスト 値名 : {{Click URL}}

dataLayerは以下のようにオブジェクトの配列となっています。
GTMではdataLayerにpushされるeventを検知して、そのeventに含まれる情報を元にタグを配信します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2998651/3f7372a9-7f12-443d-95ba-5d30a237a07c.png)

例のGA4イベントがGA4に送られる際には、
test_clickというイベント名に対して、dataLayerのgtm.elementUrl,gtm.elementClasses, gtm.elementTargetなどの値を紐づけて送信されるというイメージです。

ここで疑問が生まれます。


:::note info
疑問➀配列になっているdataLayerの値にどのようにGTMはアクセスしているのか？
:::


:::note info
疑問➁ブラウザが持つdataLayerという領域にあるデータ全ての情報をGTMで扱えるのか？
:::

この疑問を解決していきます。

# GTMのdataLayerへのアクセス方法とアクセス出来る値を理解する

前述したようにdataLayerは配列の形になっており、そのdataLayerの値にアクセスするには基本的には以下のように行います。dataLayerというブラウザ内のオブジェクト配列の10番目の"gtm.elementId"というキーの値を出力するという意味となります。

```javascript
console.log(dataLayer[10]["gtm.elementId"])
```

しかし、GTMはdataLayer配列の〇番目の場所にアクセスするという形でdataLayerの値にアクセスすることは行っていません。
GTMはdataLayerとGTMの中間に"**data model**"という領域を設けて、この領域を介してアクセスします。

これは、**dataLayer配列を一つにまとめたオブジェクト**であるとイメージが出来ます。
どのように一つにまとめるかというと、dataLayerのキーごとに最新の値を保持するというものです。

例えば、以下のようにdataLayerにpushされているとします。これはユーザがpageviewイベントを記録し、その後3回のクリックを行った後のdataLayer配列です。

```javascript
1. {userid : "12345", username : "hoge"}
2. {event : "pageview", pagelocation : "https://hogehoge.com"}
3. {event : "gtm.click", gtm.elementid : 1, gtm.elementUrl : "https://fuga1.com"}
4. {event : "gtm.click", gtm.elementid : 2, gtm.elementUrl : "https://fuga2.com"}
5. {event : "gtm.click", gtm.elementid : 3, gtm.elementUrl : "https://fuga3.com"}
```

この時3回目のクリックイベントにて扱えるデータレイヤの値について考えます。
データレイヤ配列が一つにまとめられ、以下のような値となります。

```
{
 userid : "12345", 
 username : "hoge", 
 pagelocation : "https://hogehoge.com",
 event : "gtm.click", 
 gtm.elementid : 3, 
 gtm.elementUrl : "https://fuga3.com"
 }
```

キーごとに最新の値が保持されているのが分かると思います。これがdata modelのイメージです。
GTMはdataLayerに値がpushされるたびにdata modelを更新します。
このdata modelの値がGTMにてアクセス出来るdataLayerの値となります。

そして、このdata modelに対してGTMはアクセスしてGA4にデータを送信するという仕組みになっています。

## 【まとめ】2つの疑問への回答

### 疑問➀配列になっているdataLayerの値にどのようにGTMはアクセスしているのか？

data modelという領域を介してGTMはdataLayerの値にアクセスする。
そのため、配列の〇番目の値を取得するというようなアクセス方法はとっていない

### 疑問➁ブラウザが持つdataLayerという領域にあるデータ全ての情報をGTMでアクセス出来るのか？

data modelの値のみGTMで扱える。
- dataLayerの全ての情報にアクセス出来るわけではない
- dataLayerに直接アクセスしているわけではない
- dataLayerに値がpushされるごとにdata modelが更新される
- data modelの値はキーごとに最新の値のみである

## tips

### ➀ブラウザの検証ツールconsoleタブにてdata modelの値を一覧化する

以下を実行することでその瞬間のdata modelの値一覧を確認できます

```javascript
function getDataLayerKeys() {
  const keys = [];
  if (window.dataLayer && Array.isArray(window.dataLayer)) {
    window.dataLayer.forEach(item => {
      if (item && typeof item === 'object') {
        Object.keys(item).forEach(key => {
          if (!keys.includes(key)) {
            keys.push(key);
          }
        });
      }
    });
  }
  return keys;
}

const dataLayerKeys = getDataLayerKeys();

const gtmobj = google_tag_manager["GTM-123456"].dataLayer
dataLayerKeys.forEach(key => console.log(`${key}:${gtmobj.get(key)}`))
```

### ➁もう少し詳しく知りたい方へ

こちらのページを私は参考にさせていただきました。
https://www.simoahava.com/analytics/google-tag-manager-data-model/