🐡

Experience Cloud のトラッキングデータを Data Cloud に連携する

に公開

TL;DR

Experience CloudサイトのトラッキングデータをData Cloudに連携する方法を、サイトのフレームワーク別に解説します。

  • LWRサイト:設定画面から数クリックで連携完了(ノーコード)
  • Auraサイト:WebSDKの手動実装が必要(SPAの特性による制約あり)

Experience Cloudとは何か?

Experience Cloudは、企業が顧客、パートナー、従業員向けに、セルフサービスや協業を可能にするブランド独自のデジタルエクスペリエンス(ポータルサイト、ヘルプセンター、フォーラムなど)を迅速に構築・提供するためのSalesforceプラットフォームです。Salesforce CRMと直接連携することで、既存の顧客データを活用したパーソナライズされた体験を実現し、顧客エンゲージメントの向上やビジネスプロセスの効率化に貢献します。

Experience Cloudサイトの構築フレームワーク

Experience Cloudサイトは、要件に応じて3つのフレームワークから選択して構築できます。

1. Experience Builderサイト
これは、Experience Builderというツールを使ってカスタマイズするテンプレートベースのサイトです。さらに、その基盤によって2種類に分かれます。
- LWRサイト(Lightning Web Runtime)
これは、最新のLWRベースのテンプレート(「Build Your Own (LWR)」や「Microsites (LWR)」など)を使って構築されるサイトです。
2022年冬以降に作成された新しいLWRサイトは、「Enhanced LWRサイト」と呼ばれ、強化されたサイトおよびコンテンツプラットフォームでホストされます。
- Auraサイト
これは、Salesforceの初期からあるAuraベースのテンプレート(「Customer Service」「Partner Central」「Customer Account Portal」など)を使って構築されるサイトです。

2. Visualforceサイト
以前は「Salesforce Tabs + Visualforceサイト」と呼ばれていました。これは、開発者がVisualforceという独自のプログラミング言語を使って開発するサイトです。

フレームワークによってページのフロントエンドの構造の関係でトラッキング方法が異なります。
本記事では、上記のうち「1」にフォーカスして解説していきます。


a. LWRサイト(Lightning Web Runtime)

LWR (Lightning Web Runtime) で構築された Experience Cloud サイトは現在ノーコードでData Cloudにトラッキングデータを連携することが可能です。トラッキングデータとは、WebSDKがData Cloudに渡すサイト内のユーザー情報や行動データのことを指しています。
https://help.salesforce.com/s/articleView?id=experience.exp_cloud_data_cloud.htm&type=5

a-1. LWRサイトとData Cloudの連携を開始

こちらのページのトラッキングデータをData Cloudに渡します。

ビルダー > インテグレーション > Data Cloudパネルから「サイトに追加」をクリック

15分ほどすると連携開始の旨のメールが届きます。

Data Cloud連携が「有効」になっています。

ビルダーでトグルボタンを有効にする。その後、公開をクリックします。

a-2. Data Cloudの確認

スキーマ生成の確認

Data Cloud設定 > Web サイトおよびモバイルアプリケーション ページで、Experience Cloud連携用の設定が作成されています。キャプチャのように、スキーマが自動的に生成されます。

データストリームの確認

データストリームが自動再生されています。

一例として、Engagement系のデータで200程度のデータマッピングも自動生成されています。

a-3. データの取り込み確認

クエリエディターを利用して取り込みデータの確認をします。ページ閲覧など多様なイベントが連携されてきていますね。


b. Auraサイト

Aura ベースのExperience Cloud サイトには、現在ノーコードの設定が利用できないため、Data CloudのWebSDKを組み込む必要がございます。

AuraサイトはSPA(Single Page Application)という技術で構築されており、従来のウェブサイトとは動作が異なります。

従来のウェブサイト:ページ移動のたびに新しいHTMLファイル全体を読み込む
SPAサイト:最初に基本的なHTMLとJavaScriptだけを読み込み、その後は必要なコンテンツのみを動的に取得・表示する

この仕組みにより、ページ遷移がスムーズになる一方で、トラッキングには特別な配慮が必要になります。

このJavaScriptが読み込まれると、そのページに必要なコンテンツだけをサーバーから取得し、動的にページ内に書き出します。その結果、ユーザーはページ全体が再読み込みされることなく、スムーズに画面が切り替わるようになります。

なぜSPAでトラッキングが難しいのか?

問題点:WebSDKが読み込まれた時点では、トラッキング対象のコンテンツ(ボタンやリンクなど)がまだページ上に存在しない

解決策:コンテンツの表示完了を検知してから、WebSDKを実行するタイミング制御が必要

これが、Auraサイトで手動実装が必要な理由です。

つまり重要なのは、ページにコンテンツが出力されてから、WebSDKがトラッキングを開始する必要があるということです。従来のウェブサイトでのトラッキングは、ページ読み込み時に、必要なトラッキング要素(クリック対象のボタンなど)が読み込まれているのに対し、SPAではSDKが読み込まれたタイミングでは対象となるHTMLがページ内に出力されていない可能性があります。よって、コンテンツが完全にレンダリングされたことを検知してからSDKを実行するなど、SDKの実行タイミングを制御する必要がでてきます。

実行タイミングの制御については、SalesforceのHelpページ (Experience Cloud の Personalization (旧称Interaction Studio) 連携の記事 )の内容を参考にしています。ページ内にGitHubへのリンクもあり、そちらからサンプルソースコードにもアクセスできます。

b-1. Experience Cloud への Data Cloud WebSDK 埋め込み

Data Cloud設定 > Web サイトおよびモバイルアプリケーション > カスタム Web サイトを選択。

WebSDKのScriptタグを取得し、コピーします。

Experience Cloud > ビルダー > 詳細 > ヘッドマークアップを編集 から次のように <script src=""></script> にURLを差し替えて、保存します。dataCloudExperienceCloudHelpers は単純に変数を設定していますが、let userDataをそのまま書いても問題ないです。
保存しようとすると、セキュリティ系のエラーが出ると思いますので、次のステップを参照してください。

Data Cloudに対する通信が発生するため、CSPの緩和とURLの登録が必要です。

CSPの緩和については、次を参照します。CSP (コンテンツセキュリティポリシー)はウェブサイトが読み込むリソース(JavaScript、CSS、画像、フォントなど)のソースを制限することで、クロスサイトスクリプティング(XSS)などの様々なコンテンツインジェクション攻撃を防ぐセキュリティ機能です。

信頼済みサイト URLの登録は2箇所設定する必要があります。
Experience Cloud > ビルダー > セキュリティとプライバシー > スクリプト用の信頼済みサイト

設定 > 信頼済みURL から https://cdn.c360a.salesforce.com を登録

b-2. LWCコンポーネントとSitemapの設定

ここからフロントエンドとLWCコンポーネントの知識が必要なので、わからない方は調べながら読みすすめてください。

実装の流れ

  1. ページ読み込み開始:基本的なHTML構造とJavaScriptを読み込む
  2. コンテンツの動的生成:JavaScriptがページ内容を動的に生成・表示
  3. 完了通知:LWCコンポーネントがコンテンツ表示の完了をCustom Eventで通知
  4. トラッキング開始:Sitemapがイベントを受け取り、WebSDKによるトラッキングを開始
    補足: Sitemapとは、サイト内のどのデータを取得してData Cloudへ渡すのかを定義するJavaScriptのソースコードであり、組み込みサイトの構造に合わせて実装する必要があります。

「3」のステップで、「2」完了を通知させるCustom Eventを飛ばすLWCを作成し、Experience Cloudに埋め込む必要があります。
下記は、Personalization用のExperience Cloud Solution KitのGitHubで公開されているコードとなります。
https://github.com/salesforce-experiencecloud/interaction-studio-content-personalization/blob/master/force-app/main/default/lwc/interactionStudioDataCapture/interactionStudioDataCapture.js

GitHubのコードはPersonalization用途のため、下記は一部をData Cloud用に書き直しております。

import { LightningElement, wire } from 'lwc';
import userId from '@salesforce/user/Id' 
import { getRecord } from 'lightning/uiRecordApi';

export default class InteractionStudioDataCapture extends LightningElement {
    connectedCallback() { // --- ⭐️
        document.dispatchEvent(new CustomEvent('lwc_oncomponentready', {
            bubbles: true,
            composed: true			
        }));
    }

    @wire(getRecord, { recordId: userId, layoutTypes: ['Full'], modes: ['View'] })
    wiredRecord({ error, data }) {
        if (!userId) {
            this.initDataCloud(null);
        }
        else if (data) {
            this.initDataCloud(data);
        }
        else if (error) {
            console.debug('wiredRecord error: ', error);
        }
    }

    initInteractionStudio(userData) {
        const event = new CustomEvent('lwc_onuserdataready', {
            bubbles: true,
            composed: true,
            detail: { userData: userData }
        });
        
        document.dispatchEvent(event);

        document.addEventListener('interactions:onInit', () => {
            setTimeout(() => {
                document.dispatchEvent(event); 
            }, 100);
        });
    }
}

⭐️ connectedCallback は React でいうところの ComponentDidMount(近年だと useEffectあたり) に似ています。つまり、コンテンツがページのDOMに挿入された直後にlwc_oncomponentready というイベントを発火させています。

「4」では lwc_oncomponentready が呼ばれたタイミングでSDKの初期化を実行しています。
下記は、GitHubで公開されているコードとなります。
https://github.com/salesforce-experiencecloud/interaction-studio-content-personalization/blob/master/interactionstudio/sitemap-example.js

GitHubのコードはPersonalization用途のため、下記は一部をData Cloud用に書き直しております。

document.addEventListener('lwc_onuserdataready', (e) => {
    if(isSitemapInitialized) return;
    
    isSitemapInitialized = true;

    dataCloudExperienceCloudHelpers.userData = e && e.detail && e.detail.userData;

    SalesforceInteractions.initSitemap(config);

    setInterval(() => {
        if(currentUrl !== window.location.href){
            currentUrl = window.location.href;
            SalesforceInteractions.reinit({
              global,
              pageTypeDefault,
              pageTypes,
            })
        }
    }, 1000);
});

Data Cloud用に以下のLWCを作成します。

// dataCloudDataCapture.js
import { LightningElement, wire } from 'lwc';
import userId from '@salesforce/user/Id'
import { getRecord } from 'lightning/uiRecordApi';

export default class DataCloudDataCapture extends LightningElement {
  connectedCallback() {
    document.dispatchEvent(new CustomEvent('lwc_oncomponentready', {
      bubbles: true,
      composed: true
    }));
  }

  @wire(getRecord, { recordId: userId, layoutTypes: ['Full'], modes: ['View'] })
  wiredRecord({ error, data }) {
    if (!userId) {
      this.initDataCloud(null);
    }
    else if (data) {
      this.initDataCloud(data);
    }
    else if (error) {
      console.debug('wiredRecord error: ', error);
    }
  }

  initDataCloud(userData) {
    const event = new CustomEvent('lwc_onuserdataready', {
      bubbles: true,
      composed: true,
      detail: { userData: userData }
    });

    document.dispatchEvent(event);

    document.addEventListener('interactions:onInit', (e) => {
      setTimeout(() => {
        document.dispatchEvent(event);
      }, 100);
    });
  }
}
// dataCloudDataCapture.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
</LightningComponentBundle>

このLWCをデプロイし、Experience CloudのコンポーネントとしてFooterに埋め込みます。

そして Sitemap でSDK初期化処理を下記のように書き換えます。

SalesforceInteractions.init({
  cookieDomain: 'サイトのドメイン',
  consents: [{
    provider: 'ExampleProvider',
    purpose: 'Tracking',
    status: SalesforceInteractions.ConsentStatus.OptIn,
  }]
}).then(() => {
  SalesforceInteractions.setLoggingLevel(5)
  const { 
    cashDom,
    listener, 
    resolvers,
    sendEvent,
    util,
    CartInteractionName,
    CatalogObjectInteractionName,
    OrderInteractionName,
  } = SalesforceInteractions

  let locale = (() => {
      return navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;
  })();

  const global = {
    onActionEvent: (event) => {
        const userData = dataCloudExperienceCloudHelpers.userData;

        if(userData){
            event.user = event.user || {};
            event.user.attributes = event.user.attributes || {};
            event.user.attributes.firstName = (userData?.fields?.FirstName?.value || '').trim();
            event.user.attributes.lastName = (userData?.fields?.LastName?.value || '').trim();
            event.user.attributes.experienceCloudUserId = userData?.id;
            event.user.attributes.eventType = 'identity';
            event.user.attributes.category = 'Profile';
            event.user.attributes.isAnonymous = 0;
        }
        return event;
    },
    listeners: [],
  };
  
  const pageTypeDefault = {
    name: "DefaultPage",
    interaction: {
      name: "DefaultPage",
    }
  };

  const pageTypes = [
    {
      name: "HomePage",
      isMatch: () => /consumer/.test(window.location.href),
      interaction: {
          name: 'viewed_homepage',
          eventType: 'browse',
          pageName: 'Homepage',
          pageType: 'Homepage',
          pageView: '1'
      }
    },
  ]

  let currentUrl = window.location.href;
  let isSitemapInitialized = false;
  
  document.addEventListener('lwc_onuserdataready', (e) => {
    if(isSitemapInitialized) return;
    isSitemapInitialized = true;
    dataCloudExperienceCloudHelpers.userData = e && e.detail && e.detail.userData;

    SalesforceInteractions.initSitemap({
        global,
        pageTypeDefault,
        pageTypes,
    })


    setInterval(() => {
        if(currentUrl !== window.location.href){
            currentUrl = window.location.href;
            SalesforceInteractions.reinit({
              global,
              pageTypeDefault,
              pageTypes,
            })
        }
    }, 1000);
  });
})

実装に必要な3つのステップ

Auraサイトでのトラッキング実装には、以下の3つのステップが必要です:

  1. Experience Cloud側にSDKの埋め込みをします。
  2. Salesforce CLIを利用して dataCloudDataCapture.js を含むLWCをCRMにデプロイします。
  3. Sitemapの実装をします。

データストリームを作成します(作成後のキャプチャとなっているため、データの項目が表示されていませんが、作成時は定義したデータ項目の一覧が表示されます)。

データが取り込まれていることが確認できました。

Discussion