Adobe Client Data Layer連携

ページの情報やユーザー操作を、いわゆるタグマネージャー(Adobe Launch、GTM等)に橋渡しするためのデータレイヤーとして、Adobe Client Data Layer(公式npmパッケージ、以下ACDL)を採用しています。

初期化

src/layouts/Base.astro<head>内、他のどのスクリプトよりも先に初期化します。

<script is:inline define:vars={{ pageContext }}>
  window.adobeDataLayer = window.adobeDataLayer || [];
  window.adobeDataLayer.push({ page: pageContext });
</script>
<script>
  import '@adobe/adobe-client-data-layer/dist/adobe-client-data-layer.min.js';
</script>

window.adobeDataLayerを配列として先に初期化し、そこにpageコンテキストをpushしてから、ACDL本体を読み込みます。ACDL本体は既存の配列を検知して、push/getState/addEventListenerを持つ本来のオブジェクトに拡張します(公式推奨の初期化パターンです)。

pageContextはページのfrontmatter(title/pageType)から供給されます。eventキーを持たないpushは「状態」としてマージされ、履歴には残りません。

window.adobeDataLayer.push({
  page: {
    pageName: string,
    pageType: string,   // "top" | "product" | "cart" | ... (frontmatterのpageTypeと同じenum)
    locale: string,      // 多言語対応時のみ
  },
});

イベントのpush: 2つのパターン

判断基準は「横断的な状態変化(ページ/カート/会員セッション)か、Blockローカルな操作か」です。

パターンB: Block直接push(推奨、まずはこちらを検討)

モーダルの開閉・タブ切り替え・アコーディオンのトグルなど、個々のBlock内で完結する操作は、Blockの<script>から直接pushします。

// src/lib/acdl.ts
export function pushEvent(eventName: string, payload: Record<string, unknown> = {}): void {
  window.adobeDataLayer.push({ event: eventName, ...payload });
}
<!-- 例: src/blocks/accordion/index.astro -->
<script>
  import { pushEvent } from '../../lib/acdl';

  document.querySelectorAll('.accordion__item').forEach((item) => {
    item.addEventListener('toggle', () => {
      const label = item.querySelector('.accordion__title')?.textContent ?? '';
      pushEvent('accordion_toggle', { blockName: 'accordion', label, state: item.open ? 'open' : 'closed' });
    });
  });
</script>

イベント名の強制フォーマットはありませんが、<blockname>_<action>(例: accordion_toggle)を推奨します。新しいBlockを追加するたびに中央側を修正する必要がなく、「ディレクトリを1つ足すだけ」というBlockの設計思想と整合します。

パターンA: 中央集権ブリッジ(横断的な状態変化)

カート状態の変化、会員のログイン/ログアウト、ページ到達によるライフサイクルイベント(view_item/begin_checkout/purchase)など、特定のBlockに閉じない変化は、中央の1箇所にまとめます。commerceモジュールのacdl-bridge.tsとmemberモジュールのacdl-bridge.tsがいずれもこの実例です。

cart.ts (状態管理。ベンダー非依存)
   ↓ window.dispatchEvent(new CustomEvent('cart:change', ...))
acdl-bridge.ts (ACDL特化のマッピング層)
   ↓ window.adobeDataLayer.push({ event: 'add_to_cart', ... })
adobe-client-data-layer

状態管理モジュール(cart.tsmember.ts)自身はACDLの存在を一切知りません。汎用イベント(cart:changemember:login等)を発火するだけです。ツールを乗り換える場合も、書き換えが必要なのはブリッジ層だけで済みます。

中央集権ブリッジのモジュールは、そのイベントが発生しうる全ページで明示的にimportする必要があります。静的サイトはページ遷移のたびに全JSが読み込み直されるため、共通レイアウトから自動で読み込まれるわけではありません(memberモジュールのacdl-bridge.tsは例外的に、member.enabled時に全ページへ差し込まれるMemberOverlay.astroから読み込まれているため、実質的にどのページでもimport漏れが起きません)。

ECライフサイクルイベント(commerceモジュール、page/イベント本体)

commerceモジュールを使うサイトでは、以下のイベントが発火します。

  • view_item — PDPページ読み込み時。PDPページの初期化スクリプトが直接push
  • add_to_cart — カートに追加/数量増加時。commerceacdl-bridge.tsがpush
  • remove_from_cart — カートから削除/数量減少時。commerceacdl-bridge.tsがpush
  • begin_checkout — チェックアウトページ(/commerce/cart/checkout)読み込み時。同ページの初期化スクリプトが直接push
  • purchase — 注文完了ページ(/commerce/order)読み込み時。同ページの初期化スクリプトが直接push

add_to_cartのペイロード例です。

window.adobeDataLayer.push({
  event: 'add_to_cart',
  product: { sku, name, categories, price, currency, quantity },
});

purchaseのペイロード例です。

window.adobeDataLayer.push({
  event: 'purchase',
  order: { orderId, currency, total, items: [{ sku, name, price, quantity }] },
});

詳しくはcommerceモジュールを参照してください。

user名前空間(memberモジュール)

member機能(site.config.tsmember.enabled)を使うサイトでは、ログイン中の会員情報をuser名前空間としてpushします。担当はsrc/modules/member/lib/acdl-bridge.tsで、member.tsが発火するmember:login/member:logout(ベンダー非依存のCustomEvent)を購読し、変換します。

  • ログイン時 — window.adobeDataLayer.push({ user: { id: member.id, ...member.attributes } })。会員発行ページで設定した属性(attributes)がそのままuserオブジェクトに展開されます
  • ログアウト時 — window.adobeDataLayer.push({ user: null })

pageと同様、eventキーを持たないpushなので「状態」としてマージされ、履歴には残りません。タグマネージャー側からは「現在ログイン中かどうか、ログイン中なら誰か」という状態として参照する使い方を想定しています。

window.adobeDataLayerはページ単位(フルページ遷移で消える)なので、pageコンテキストと同様、ページの読み込み時点で既にログイン中ならuser状態を再pushします。これが無いと、たとえば会員発行ページのクイックログインから別ページへ遷移した直後に、遷移前のページでpushしたuser情報が新しいページのadobeDataLayerに反映されない、という問題が起こります。

memberモジュールのacdl-bridge.tsは、member.enabled時に全ページへ差し込まれるMemberOverlay.astroから読み込まれています。そのため、ログイン/ログアウトが会員発行ページ・ログインページ・オーバーレイ自身のどこで起きても、確実にACDLへ届きます(中央集権ブリッジのimport漏れが構造的に起きないケースです)。会員機能全体の詳しい説明は会員機能(ログインダミーシステム)を参照してください。

マーケティングタグの注入(タグマネージャー本体等)

Adobe Launch/GTM等のタグ本体は、コードを直接編集せずsite.config.tsで設定します。Base.astroが、ACDL初期化の・他のどのスクリプトよりにこの設定を出力するため、タグマネージャーが読み込まれる時点でwindow.adobeDataLayerが必ず存在する状態が保証されます。

新しいイベントを追加する

  1. パターンA/Bのどちらかを判定する
  2. パターンBなら該当Blockの<script>pushEvent()を追記、パターンAなら中央のブリッジ層に購読処理を追加(パターンAの場合はimportの配線を忘れないこと)
  3. 実際にpushされることをブラウザの開発者ツール等で確認する

動作確認方法

Playwrightなどでpushを検証する場合は、ACDL本体の読み込みに「関数push」でリスナー登録を仕込みます(ACDLはtypeof item === 'function'のpushをFCTNアイテムとして認識し、ライブラリ初期化時にdataLayerインスタンスを引数に実行します)。window.adobeDataLayer.push自体を独自関数で上書きする方式は、ライブラリ初期化時にその上書きが失われるため使えません。

await page.addInitScript(() => {
  window.adobeDataLayer = window.adobeDataLayer || [];
  window.__acdlEvents = [];
  window.adobeDataLayer.push((dataLayer) => {
    dataLayer.addEventListener('adobeDataLayer:change', (event) => {
      window.__acdlEvents.push(event);
    });
  });
});

将来の拡張

CMPの同意状態は、consentといった新しい名前空間を追加でpushするだけで対応できる設計になっています(既存のpage/user/イベント構造の変更は不要)。現時点ではこのスキーマは未設計です。