「バナーの画像をA/Bテストしたい」「どのキャッチコピーがクリックされるか計測したい」 こうしたマーケティング要望に応えるため、LWC(Lightning Web Component)とカスタムオブジェクトを組み合わせて、実用的なA/Bテスト基盤を構築しました。
今回は、以下の要件を満たすコンポーネントの実装方法を共有します。
- Salesforce CMS連携: A/BそれぞれのCMS画像をプロパティで選択できる。
- 計測機能: 「表示数」と「クリック数」を自動記録する。
- UU計測: ブラウザ単位でユニークユーザーを識別し、実績の重複を防ぐ。
- デザイン調整: 画像の高さやトリミング位置(top/center/bottom)をビルダーで調整可能。
- ビルダー対応: 編集中はA/Bどちらかを強制表示できるプレビューモード搭載。プレビューモード中の操作は計測対象外となる。※公開前に「Auto」に戻す必要があるので注意。

アーキテクチャ概要
- フロントエンド (LWC):
- A/Bパターンの振り分け(ランダム)
- Visitor ID(UUID)の生成とLocalStorage保存
- Salesforce CMS画像のURL解決(LWR制限の回避)
- バックエンド (Apex):
- 権限を持たないゲストユーザーからのログ書き込み(
without sharing) - ユニークキーによる重複排除(
upsert)
- 権限を持たないゲストユーザーからのログ書き込み(
- データベース (Custom Object):
- 実績データの格納
今回の記事で作成したコンポーネントの全ソースコードをGitHubで公開しています。 ぜひ Clone して、あなたの組織で動かしてみてください。
カスタムオブジェクトの作成
実績を記録するためのA/B Test Logオブジェクト AB_Test_Log__c を作成します。
| 項目ラベル | 項目名 (API) | データ型 | 備考 |
| Test ID | Test_Id__c | テキスト(100) | テスト識別ID |
| Variant | Variant__c | テキスト(10) | ‘A’ or ‘B’ |
| Action Type | Action_Type__c | 選択リスト | ‘View’, ‘Click’ |
| Visitor ID | Visitor_Id__c | テキスト(255) | ブラウザ識別ID |
| Unique Key | Unique_Key__c | テキスト(255) | 外部ID / ユニーク(重複不可) |
※ Unique_Key__c を「外部ID」かつ「ユニーク」に設定することが、正確な計測の肝です。
Apexコントローラーの実装
ゲストユーザーでも書き込みができるよう without sharing を宣言し、upsert を使って重複レコードの作成を防ぎます。※ゲストユーザーでは Update は発生しません。
/**
* @description : A/Bテストの実績ログを管理するコントローラー
* ゲストユーザーによる書き込みを許可するため without sharing を適用
*/
public without sharing class AbTestLogger {
/**
* @description A/Bテストの表示またはクリックイベントを記録します。
* Unique_Key__c を使用して Upsert を行い、同一ビジターによる重複カウントを防止します。
* @param testId テストを識別するID
* @param variant 表示されたバリエーション ('A' または 'B')
* @param actionType アクションの種類 ('View' または 'Click')
* @param visitorId ブラウザ固有のビジターID
*/
@AuraEnabled
public static void logAction(String testId, String variant, String actionType, String visitorId) {
// 必須パラメータのチェック
if (String.isBlank(testId) || String.isBlank(variant) || String.isBlank(visitorId)) {
return;
}
try {
AB_Test_Log__c log = new AB_Test_Log__c();
// 基本情報のセット
log.Test_Id__c = testId;
log.Variant__c = variant;
log.Action_Type__c = actionType;
log.Visitor_Id__c = visitorId;
// ユーザー種別の判定
// UserInfo.getUserType() はゲストの場合 'Guest' を返します
log.User_Type__c = (UserInfo.getUserType() == 'Guest') ? 'Guest' : 'Auth';
// 重複排除キーの生成 (TestID + Action + VisitorID)
log.Unique_Key__c = testId + '_' + actionType + '_' + visitorId;
// ユニークキーに基づいてUpsert実行
upsert log Unique_Key__c;
} catch (Exception e) {
System.debug(LoggingLevel.ERROR, 'AB Test Logging Failed: ' + e.getMessage());
}
}
}
LWCの実装
LWRサイトでCMS画像を表示する際、lightning/cmsDeliveryApi ワイヤーアダプタを使用すると LWR3021 エラー(モジュール未定義)が発生することがあります。 そのため、APIを使わず、標準的なパスルールに基づいてURLを生成する方式を採用しています。
constructCmsUrl(contentKey) {
if (!contentKey) return null;
const sitePrefix = (basePath && basePath !== '') ? basePath : '';
return `${sitePrefix}/sfsites/c/cms/delivery/media/${contentKey}`;
}
運用時の注意点(ここが重要!)
「ゲストユーザーだとレコードが作成されない」という問題に直面しないために、 LWRサイトでゲストユーザーがレコードを作成(Insert)するには、以下の設定が必須です。
ゲストユーザーに権限を割り当て
ゲストユーザープロファイルに対して以下の権限を付与してください。
- Apexクラス
AbTestLoggerの実行権限を付与 - A/B Test Logオブジェクト作成権限を付与
- A/B Test Logオブジェクト項目レベルセキュリティを付与
- Apexクラス権限を付与
- オブジェクト作成権限を付与
- 項目レベルセキュリティ



キャッシュの考慮
設定を変更したり、Apexクラスをデプロイした直後は、LWRサイトの強力なCDNキャッシュにより変更が反映されないことがあります。 「設定は合っているのに動かない」という場合は、サイトを「公開」してから15分ほど待って再度テストしてみてください。
分析してみる
ユーザーの画面操作によって作成されたA/B Test Logオブジェクトレコードを使用して、画像のようなレポートを作成できます。
画像の例では、特定の Test ID を対象にAのパターンとBのパターンでそれぞれViewとClickがどれくらいの割合で発生したのかを分析するためのレポートを表示しています。

まとめ
このコンポーネントを使えば、Data Cloudなどの外部ツールを導入する前の段階でも、Salesforce標準機能だけで本格的なA/Bテストと効果測定が可能になります。 ぜひ、ご自身のサイトで「勝ちパターン」を見つけるために活用してみてください。



読者の声