
【第600回】Personalization:Affinity を使って Hero Banner を切り替える
前回の記事では、TrailNest の商品閲覧・カート追加・購入をもとに、カテゴリへの Calculated Affinity を作成しました。
今回は、そのスコアを実際の Web 接客に使用します。
TrailNest のトップページにある Hero Banner を、通常バナーと 6 カテゴリの、計 7 種類で出し分けます。
通常バナー
Backpacks バナー
Tents バナー
Sleeping バナー
Apparel バナー
Footwear バナー
Accessories バナー
これまでに用意した「顧客と行動のデータ」を、Web サイトの「表示内容」につなげる回です。
Personalization 基礎シリーズ
Sitemap Builder シリーズ
Data 360 設定シリーズ
Personalization 設定シリーズ
今回の出し分け方
今回は、カテゴリごとの raw_affinity_score が最も高いカテゴリのバナーを表示します。
例えば、backpacks が 15、sleeping が 12 なら Backpacks バナーです。その後、Sleeping の購入などで sleeping が 17 になれば、更新されたスコアを使う次の Personalization Request では Sleeping バナーを選ぶ構成です。
比較する値:raw_affinity_score
選ぶカテゴリ:スコアの降順に並べた先頭の Category
Affinity のレコードがない場合:通常バナー
対応していないカテゴリが返った場合:通常バナー
affinity_score は 0 〜 100 に収まる値です。例えば raw が 101 と 150 でも、affinity_score はどちらも 100 になります。そのため、今回の順位付けには頭打ちになる前の raw_affinity_score を使用します。
同点の場合、raw の降順だけでは同点内の順番は決まりません。今回は同点の最高スコアのカテゴリのいずれかが返ればよいとします。本番で同点時の順番も固定する場合は、差し込み項目の設定で第2の並び順を指定できるか確認し、Category の昇順などを加えます。設定できていない順番を保証するものとしては扱いません。
最高スコアのカテゴリを返す方法
Salesforce Personalization の Decision には、Calculated Insight を差し込み項目として使用し、その複数の値に並び順を指定する機能があります。
今回はこの機能を使い、Category を返す差し込み項目を raw_affinity_score の降順で設定します。7 つの Decision を競わせるのではなく、1 つの Decision から最高スコアのカテゴリを返し、そのカテゴリに対応する表示を Experience Template で選びます。
各機能の役割
例えば、顧客に合わせてバナーを変えたいとします。そのバナーに必要なのは、次の 3 つの値だったとします。
見出し
画像 URL
リンク URL
この値を用意して表示するまでを、各設定で分担します。
1. Content Schema:値を入れる項目を用意する
「変数」を用意するような設定です。
例えば、Title、Image_URL、Link_URL という項目を定義します。この段階では「Title に何が入るか」は決まっていません。まず、値を受け渡すための項目名を決めます。
2. Personalization Decision:その項目に入れる値を決める
顧客に応じて、変数の中身を決めるような設定です。
例えば、キャンプに興味がある顧客には、次の値を返します。
Title:キャンプへ出かけよう
Image_URL:テントの画像 URL
Link_URL:キャンプ用品のページ URL
項目名は同じでも、中身が顧客によって変わります。
3. Personalization Point:Web サイトからの呼び出し先を作る
Web サイト上の JavaScript は、Salesforce に「この顧客に合う内容を返してください」とリクエストを送ります。
その際に、どの Personalization の設定を使うかを、Point の API 名で指定します。例えば、バナー用の Point を指定すれば、Salesforce はその Point に結び付いた顧客データ・Content Schema・Decision を使って、返す値を決めます。
Point は、これらの設定をまとめた箱のようなものです。Web サイト側は、その名前を指定することで、必要な設定をまとめて利用できます。
4. Experience Template:受け取った値を画面に当てはめる
変数の値を使って、バナーの見た目を作ります。
例えば、Title の値を見出しとして表示し、Image_URL の画像を背景に使い、ボタンのリンク先に Link_URL を設定します。文字の大きさや色、レイアウトも、ここで決めます。
5. Web Personalization Manager:バナーを置く場所を決める
作ったバナーを、Web サイトのどこに表示するかを設定します。
例えば、「トップページの上部にあるバナーを、この内容に置き換える」と指定します。
まとめると、Content Schema で項目を用意し、Decision で中身を決め、Point から取得し、Template に当てはめ、WPM で指定した場所に表示する、という関係です。

① Hero Banner の画像を用意する
今回は、TrailNest の緑を基調としたデザインに合わせ、写真調の画像を用意します。
通常バナー
画像:TN-HERO-DEFAULT.png
朝の光が差す山と湖
見出し:Gear for Every Journey
ラベル:TRAILNEST · EVERY JOURNEY

Backpacks バナー
画像:TN-HERO-BACKPACKS.png
バックパックを背負った登山者と山の景色
見出し:Carry Your Next Adventure
ラベル:TRAILNEST · BACKPACKS

Sleeping バナー
画像:TN-HERO-SLEEPING.png
夜のキャンプと寝袋
見出し:Sleep Well. Wake Wild.
ラベル:TRAILNEST · SLEEPING

Tents バナー
画像:TN-HERO-TENTS.png
朝の山と湖を見渡すテント
見出し:Make the Wild Your Home
ラベル:TRAILNEST · TENTS & SHELTER

Apparel バナー
画像:TN-HERO-APPAREL.png
オレンジのアウトドアウェアと深い森
見出し:Ready for Every Element
ラベル:TRAILNEST · OUTDOOR APPAREL

Footwear バナー
画像:TN-HERO-FOOTWEAR.png
登山靴と岩場のトレイル
見出し:Find Your Footing
ラベル:TRAILNEST · HIKING FOOTWEAR

Accessories バナー
画像:TN-HERO-ACCESSORIES.png
ボトル・コンパス・ヘッドランプと湖畔
見出し:Small Gear. Big Adventures.
ラベル:TRAILNEST · ADVENTURE ESSENTIALS

画像だけでなく、見出し、ラベル、CTA も変更します。これにより、どのバナーが表示されたかを判別しやすくします。
文字は画像に焼き込まず、HTML で表示します。これは、スマートフォンでも文字を読みやすくし、後から文言を変更できるようにするためです。
今回はバナーのために商品 Data Extension や Goods Product に新しいレコードを追加しません。7 種類の画像、見出し、CTA は今回の Experience Template に用意します。💡
② Content Schema を作成する
目的:バナーとして返す見出し、画像 URL、CTA などの項目を定義する
Personalization アプリで Content Schemas(旧名称:Response Template)を開き、New から作成します。
今回は、次の内容で設定して、次に進みます。
Personalization Type:Dynamic Content
Name:TrailNest Hero Content
API Name:TrailNest_Hero_Content

Attribute Label:Top Category
API Name:Top_Category

この項目には、画像 URL ではなく backpacks や sleeping などのカテゴリコードを返します。画像や文言は Experience Template に定義する構成です。
Content Schema は Web Connector の Schema.json とは別の設定です。今回は「Personalization が何を返すか」を定義しています。
③ Personalization Point を作成する
目的:使用する Profile Data Graph と Content Schema を指定する
Personalization Points を開き、New → Manual Setup で作成します。
Profile Data Graph:Real-Time > TrailNest Profile
Name:TrailNest Home Hero
API Name:TrailNest_Home_Hero
Personalization Type:Dynamic Content
Content Schema:TrailNest Hero Content
Authentication Required:未チェック

今回は、公開 Web サイトの Web SDK から利用する Personalization Point を作成します。
「保存して Personalization Decisions を追加する」ボタンをクリックします。Personalization Decision に対して、連続して作業ができます。
④ Personalization Decision を作成する
目的:誰にどのバナーを返すかを決める
作成した Personalization Point が開いたら、新規をクリックし、プロパティに以下を入力します。
Decision Name:TrailNest Top Category Hero
Decision API Name:TrailNest_Top_Category_Hero
Decision State:Live
- Live:Personalization のリクエスト時に評価される
- Draft:保存されていても、通常の判定には使用されない

次に、Decision Configuration の Top Category の右側にある、Add Merge Field をクリックし、次の内容で設定します。
最初の空欄は、後に自動入力されるので何も入力しないでください。
Attribute の Resource:Calculated Insights
Calculated Insight:TrailNest Category Affinity Category
返す項目:Category(Category__c)
Merge Field API Name:Top_Category
Default Text:default
Sort Criteria の項目:raw_affinity_score
Sort Order:Descending(降順)

これで保存すると、先ほど空欄のままにした Top Category の入力欄に差し込みトークンが生成されますのでそのままにしてください。次へ進みます。

Default Text の default は、計算済みインサイトから値が取得できない場合の値です。通常バナーの表示に使用します。
最後にターゲティングルールは、以下で問題ないです。保存してください。
Targeting Rules:Always(条件なし)

⑤ Experience Template を作成する
目的:返された内容を、TrailNest に合う HTML として表示する
Experience Templates を開き、新規作成を開始したら、以下を入力して次へ進みます。
Channel:Web
Name:TrailNest Top Category Hero Banner
API Name:TrailNest_Top_Category_Hero_Banner

Connected Websites:現在 TrailNest で使用している Website Connector

Template Type:Handlebars
Creation Method:Start from scratch

Content Schema:TrailNest Hero Content
その後、「変数の追加」をクリックします。

変数を次のように設定します。
Label:Top Category
API Name:Top_Category
Default Value:Attributes > Top Category

Turn off auto-engagement tracking はチェックせず、HTML コードの編集画面に、以下を貼り付けます。
<style>
.tn-hero { position:relative; isolation:isolate; overflow:hidden; min-height:520px; display:flex; align-items:center; color:#fff; background:#183426; font-family:Arial,Helvetica,sans-serif; }
.tn-hero__image { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:70% center; z-index:-2; }
.tn-hero::before { content:""; position:absolute; inset:0; z-index:-1; background:linear-gradient(90deg,rgba(10,29,20,.82) 0%,rgba(10,29,20,.58) 35%,rgba(10,29,20,.12) 68%,rgba(10,29,20,.03) 100%); }
.tn-hero__inner { box-sizing:border-box; width:100%; max-width:1200px; margin:0 auto; padding:70px 24px; }
.tn-hero__badge { display:inline-block; margin:0 0 22px; padding:9px 13px; border:1px solid rgba(255,255,255,.45); border-radius:4px; background:rgba(10,29,20,.25); font-size:12px; line-height:1.3; font-weight:700; letter-spacing:2px; }
.tn-hero__title { max-width:620px; margin:0; font-size:clamp(44px,5.4vw,74px); line-height:1.03; letter-spacing:-2.4px; font-weight:800; text-wrap:balance; color:#fff; }
.tn-hero__description { max-width:490px; margin:24px 0 28px; font-size:18px; line-height:1.6; color:rgba(255,255,255,.94); }
.tn-hero__cta { display:inline-flex; align-items:center; gap:18px; padding:15px 24px; border-radius:999px; background:#fff; color:#234b35; text-decoration:none; font-size:15px; line-height:1.4; font-weight:700; box-shadow:0 4px 18px rgba(0,0,0,.12); }
.tn-hero__cta:hover { background:#edf2e8; }
.tn-hero__cta:focus-visible { outline:3px solid #f4ce86; outline-offset:5px; }
@media(max-width:680px) {
.tn-hero { min-height:610px; align-items:flex-end; }
.tn-hero__image { object-position:78% top; }
.tn-hero::before { background:linear-gradient(0deg,rgba(8,25,17,.96) 0%,rgba(8,25,17,.72) 42%,rgba(8,25,17,.1) 85%); }
.tn-hero__inner { padding:210px 22px 38px; }
.tn-hero__badge { margin-bottom:18px; font-size:10px; letter-spacing:1.5px; }
.tn-hero__title { max-width:440px; font-size:42px; letter-spacing:-1.4px; }
.tn-hero__description { font-size:16px; margin:20px 0 24px; }
}
/* Fill the replacement area even when its host is a flex container. */
.tn-affinity-hero {
box-sizing:border-box;
display:block;
width:100%;
max-width:none;
min-width:0;
flex:1 1 100%;
align-self:stretch;
}
.tn-affinity-hero .tn-affinity-panel {
box-sizing:border-box;
width:100%;
max-width:none;
min-width:0;
}
.tn-affinity-hero .tn-hero__image {
position:absolute;
inset:0;
width:100%;
max-width:none;
height:100%;
object-fit:cover;
}
.tn-affinity-hero .tn-affinity-panel { display:none; }
.tn-affinity-hero[data-top-category="backpacks"] .tn-affinity-panel--backpacks,
.tn-affinity-hero[data-top-category="tents"] .tn-affinity-panel--tents,
.tn-affinity-hero[data-top-category="sleeping"] .tn-affinity-panel--sleeping,
.tn-affinity-hero[data-top-category="apparel"] .tn-affinity-panel--apparel,
.tn-affinity-hero[data-top-category="footwear"] .tn-affinity-panel--footwear,
.tn-affinity-hero[data-top-category="accessories"] .tn-affinity-panel--accessories { display:flex; }
.tn-affinity-hero:not([data-top-category="backpacks"]):not([data-top-category="tents"]):not([data-top-category="sleeping"]):not([data-top-category="apparel"]):not([data-top-category="footwear"]):not([data-top-category="accessories"]) .tn-affinity-panel--default { display:flex; }
</style>
<section id="home_hero" class="tn-affinity-hero" data-top-category="{{attributes.Top_Category}}" aria-label="TrailNest featured collection">
<div class="tn-hero tn-affinity-panel tn-affinity-panel--default">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-DEFAULT.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · EVERY JOURNEY</div>
<h1 class="tn-hero__title">Gear for Every Journey</h1>
<p class="tn-hero__description">Discover outdoor essentials built for trails, campsites, and everything in between.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=backpacks">Explore Backpacks <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--backpacks">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-BACKPACKS.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · BACKPACKS</div>
<h1 class="tn-hero__title">Carry Your Next Adventure</h1>
<p class="tn-hero__description">From everyday trails to the summit. Find a backpack built to go further with you.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=backpacks">Shop Backpacks <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--tents">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-TENTS.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · TENTS & SHELTER</div>
<h1 class="tn-hero__title">Make the Wild Your Home</h1>
<p class="tn-hero__description">From misty mornings to mountain sunsets. Find dependable shelter for your next escape.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=tents">Shop Tents & Shelter <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--sleeping">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-SLEEPING.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · SLEEPING</div>
<h1 class="tn-hero__title">Sleep Well. Wake Wild.</h1>
<p class="tn-hero__description">Warm nights. Fresh mornings. Discover sleeping gear made for life under the stars.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=sleeping">Shop Sleeping Gear <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--apparel">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-APPAREL.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · OUTDOOR APPAREL</div>
<h1 class="tn-hero__title">Ready for Every Element</h1>
<p class="tn-hero__description">Layer up for changing skies. Discover outdoor clothing made to move with you.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=apparel">Shop Outdoor Apparel <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--footwear">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-FOOTWEAR.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · HIKING FOOTWEAR</div>
<h1 class="tn-hero__title">Find Your Footing</h1>
<p class="tn-hero__description">Rocky trails. New horizons. Discover hiking footwear built for the journey ahead.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=footwear">Shop Hiking Footwear <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="tn-hero tn-affinity-panel tn-affinity-panel--accessories">
<img class="tn-hero__image" src="https://image.s12.sfmc-content.com/lib/fe3311727364047e721170/m/1/TN-HERO-ACCESSORIES.png" alt="" loading="lazy" decoding="async">
<div class="tn-hero__inner">
<div class="tn-hero__badge">TRAILNEST · ADVENTURE ESSENTIALS</div>
<h1 class="tn-hero__title">Small Gear. Big Adventures.</h1>
<p class="tn-hero__description">The finishing touches for every journey. Explore practical essentials for life outdoors.</p>
<a class="tn-hero__cta" href="https://mcxkknz3m0zj3jqsxn4hm3dp3q-4.pub.sfmc-content.com/f0sn3uhu0p0?view=category&category=accessories">Shop Accessories <span aria-hidden="true">→</span></a>
</div>
</div>
</section>注意事項:テンプレートでのカテゴリの参照方法
Decision が返す Top_Category は、レスポンスの attributes 配下に格納されています。今回の Experience Template では、次のように指定します。
data-top-category="{{attributes.Top_Category}}"
{{Top_Category}} と指定すると値が差し込まれず、Decision がカテゴリを正しく返していても、通常バナーが表示されます。
このファイルには、通常バナーと 6 つのカテゴリバナーの画像、見出し、説明文、CTA を用意しています。返された Top_Category を HTML の data-top-category に設定し、CSS で対応する 1 つのバナーを表示します。空欄や対応していないコードの場合は通常バナーになります。
Save & Activate で有効にします。

⑥ Web Personalization Manager で設定する
公開済み TrailNest のトップページを開き、URL に次のパラメータを付けて開くと、Web Personalization Manager が開きます。
?sf_personalization_wpm
ログインを求められた場合は、現在使用している Salesforce 環境へログインします。

右上の State は、その Experience を通常の訪問者にも配信するかどうかの設定です。
Disabled:配信を無効にした状態。まずはこの状態で設定・プレビューします。
Enabled:配信を有効にする状態。Save を押すと公開されます。
Save の動作は State によって変わります。
Disabled のまま Save:設定を保存します。通常の訪問者への配信は開始しません。
Enabled にして Save:設定を保存し、Experience を公開します。指定したページ・表示場所で Personalization が動作するようになります。
Personalization Experience を作成する
Personalization Experiences → + Add New をクリックします。

Embedded Content を選択します。

Personalization Point:TrailNest Home Hero を選択します。

Experience Template:TrailNest Top Category Hero Banner を選択します。

Location タブでは、トップページ上で次の内容を指定します。
表示対象:Current Page Type(Home)
Display Method:Replace an Element
Page Element:SECTION#home_hero(※ Selecter も利用可能です)

TrailNest は Query String によって画面を切り替えます。今回は Page Type の Home に限定し、Category や Checkout に同じ Hero を表示しないようにします。
次に、Content タブに切り替えて、次の内容を指定します。
Engagement Destination:Website Engagement

⑦ Web Personalization Manager でプレビューする
Web Personalization Manager では、公開する前に、作成した Experience が Web ページ上でどのように表示されるかを確認できます。
Preview Settings タブを開きます。
今回は、次のように設定します。
Show Overlays:有効
Personalization の表示領域を強調表示し、置き換わった場所を確認しやすくします。Show All Personalization Experiences:無効
まずは今回の Hero Banner だけを確認します。

確認する顧客の Individual ID を指定する
別の顧客のデータで表示を確認する場合は、Individual ID に、その顧客の Individual の ID を入力します。
例:5560a09008c85e5f

今回の Web 側では、identity の deviceId を Individual ID に Mapping しています。そのため、前の記事で顧客との照合を確認したブラウザの deviceId を指定して確認します。
この時は、Real-Time Profile Data Graph の JSON 上で Affinity を参照できている顧客を使用します。

Decision を選択して Preview をクリックする
ページ上部の Personalization Decisions and Cohorts のプルダウンから、今回作成した TrailNest Top Category Hero を選択します。
続いて、Preview をクリックして、トップページの SECTION#home_hero が、Experience Template の Hero Banner に置き換わるか確認します。

今回の Decision は、対象顧客の Affinity から、raw_affinity_score が最も高いカテゴリを Top Category として返す構成です。
例えば、対象顧客で backpacks が最高スコアなら、Backpacks バナーが表示されることを確認します。データがない場合は、通常バナーになります。
プレビュー後に公開する
Preview をクリックしただけでは、通常の訪問者への公開は完了していません。変更されることが確認できたら、Experience の State を Enabled にし、Save をクリックします。

いかがでしたでしょうか。
今回は、カテゴリへの Affinity をスコアの降順で参照し、最もスコアが高いカテゴリの Hero Banner を表示する構成を紹介しました。
Profile Data Graph で顧客と行動を参照し、Affinity で興味を数値化し、Decision の差し込み項目で最高スコアのカテゴリを返し、Experience Template と WPM で Web サイトへ表示します。
行動によってカテゴリの順位が逆転し、次の Personalization Request でバナーが変わることまで確認すれば、データの取得から Web 接客の表示までをつなげて検証できます。
次回は、Item Data Graph の商品情報を使用し、TrailNest に Product Recommendation を表示する設定へ進みます。
今回は以上です。