> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kameleoon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Web Experimentationで効率的なカスタムコードを書く

> Activation API、スコープを限定した実行、CSSファーストの視覚的変更を使用して、Kameleoon Web Experimentation向けの効率的でパフォーマンスの高いカスタムJavaScriptを記述します。

[Kameleoon App](https://app.kameleoon.com) には、ウェブサイト上で実行されるカスタムJavaScriptを追加できる複数のエントリーポイントがあります。本記事では、それぞれの利用可能なエントリーポイントに対する具体的な推奨事項を説明します。なお、すべてのKameleoonスクリプトはページ読み込みごとに1回実行されます。

カスタムスクリプトを実装する前に、最適化された実行のために [Kameleoon Command Queue](../../apis/activation-api-js/api-reference/command-queue) の使用を検討してください。

## Kameleoon Command Queue

KameleoonのAPIとやり取りする最も効率的な方法は、**ゴールのコンバート**、**カスタムデータの設定**、**イベントのトリガー** のいずれにおいても、タグマネージャー(例: Google Tag Manager)の既存のトリガーと Kameleoon Command Queue を組み合わせて活用することです。これは、Kameleoonに JavaScript を追加する際の主要なアプローチとすべきです。Kameleoon に長い JavaScript コードを直接書く代わりに、タグマネージャー内のたった2行のコードで同じ結果を得ることができます。

### 例

**- 売上ゴールをコンバートする**

タグマネージャーで、確認ページに売上を取得するトリガーを作成し、以下のコードを追加します:

```javascript theme={null}
// Replace kameleoonGoalID and {{revenue}} with your actual values
window.kameleoonQueue = window.kameleoonQueue || [];
window.kameleoonQueue.push(['Goals.processConversion', kameleoonGoalID, {{revenue}}])
```

GTMからゴールコンバージョンを作成する方法については、[このドキュメント](/user-manual/assets/goals/create-a-goal-conversion-tag-from-gtm) を参照してください。

**- 訪問者がログインしたときにカスタムデータ値を設定する**

Kameleoonでカスタム JS を書く代わりに、タグマネージャー経由で直接値を設定します:

```javascript theme={null}
// Replace "customDataName" and "customDataValue" with your actual values
window.kameleoonQueue = window.kameleoonQueue || [];
window.kameleoonQueue.push(['Data.setCustomData', "customDataName", "customDataValue"]);
```

**- 商品がカートに追加されたときにイベントをトリガーする**

特定のアクションに基づいて訪問者をターゲティングするためにこれを使用します:

```javascript theme={null}
// Replace "customEventName" with your actual event name
window.kameleoonQueue = window.kameleoonQueue || [];
window.kameleoonQueue.push(['Events.trigger', "customEventName"]);
```

`kameleoonQueue` を利用できない場合は、以下で詳述する各利用可能なスクリプトに対する具体的な推奨事項を参照してください。

## グローバルスクリプト & バリエーションスクリプト

### Activation API で JavaScript の実行を最適化する

Kameleoon の [Activation API](../../apis/activation-api-js/api-reference/api-reference) を活用して、適切なタイミングでバリエーションを適用します。このアプローチは、パフォーマンスの問題を防ぎ、訪問者にシームレスな体験を提供するのに役立ちます。

以下は、訪問者体験を向上させるために使用できる Activation API の重要な関数です:

* [`runWhenConditionTrue`](../../apis/activation-api-js/api-reference/api-reference#runwhenconditiontrue): 特定の条件が満たされたときにコードを実行します。デフォルトでは200ミリ秒ごとに実行されます。ただし、決して解決されない可能性のある条件には注意してください。不要なループにつながる可能性があります。関数が明示的に `true` を返すまでループは継続することに注意してください。`false` や `undefined` を返してもループは停止せず、コールバックもトリガーされません。

❌ 不正な使用法(無限ループのリスク): 以下の例では、商品ページ以外のすべてのページで `true` が返されることはなく、ループが無限に実行されます:

```javascript theme={null}
Kameleoon.API.Core.runWhenConditionTrue(() => {
    return window.dataLayer && window.dataLayer.find(layer => layer.pageType === "product");
}, () => {
    // Product page logic here
});
```

✅ 推奨されるアプローチ: 必ず true を返してループを抜け、その後コールバック内でロジックを処理します:

```javascript theme={null}
let pageTypeLayer;
Kameleoon.API.Core.runWhenConditionTrue(() => {
    pageTypeLayer = window.dataLayer && window.dataLayer.find(layer => layer.pageType);
    return pageTypeLayer; 
}, () => {
    if (pageTypeLayer?.pageType === "product") {
        // Product page logic here
    }
});
```

<Note>
  ページタイプに関する情報を取得しようとするときなど、`dataLayer` や遅延読み込みされる他のオブジェクトを待つために `runWhenConditionTrue` に依存するよりも、URL や Cookie/localStorage を使って情報を取得する方が望ましいです。このアプローチにより、より高速な実行とより良いパフォーマンスが保証されます。
</Note>

* [`runWhenElementPresent`](../../apis/activation-api-js/api-reference/api-reference#runwhenelementpresent): このメソッドは、特定の要素がDOMに存在する場合にのみコードが実行されるようにし、動的に読み込まれる要素による不要な遅延を回避します。

#### 重要な考慮事項

* デフォルトで Mutation Observer を使用します(パフォーマンスのため推奨)。
* サイトで Mutation Observer が無効になっている場合は、このメソッドの第3引数としてポーリング間隔を指定できます。
* 要素が DOM に動的に挿入される場合は、このメソッドの第4引数として `isDynamicElement` を `true` に設定します:

<Warning>
  以下のコードは控えめに、絶対に必要な場合にのみ使用してください。使用ケースは最小限に抑え、ページのパフォーマンスを最適に保つために複数の要素に同時に適用しないようにしてください。

  ページのソースコードが要素を更新するたびに変更する場合、**無限ループ** が発生する可能性があることに注意してください。
</Warning>

```javascript theme={null}
Kameleoon.API.Core.runWhenElementPresent('#myDynamicElement', ([elem]) => {
	// Logic once the element loaded
}, null, true); // isDynamicElement is set to true
```

### コードのスコープを特定のページに設定する

パフォーマンスを最適化するため、コードが関連するページでのみ実行されるようにしてください。これは `runWhenConditionTrue` や `runWhenElementPresent` のようなループベースのメソッドを使用する場合に特に重要です。これらのメソッドをサイト全体で実行すると、不要な実行が発生してパフォーマンスに影響を与える可能性があります。たとえば、dataLayer で売上情報を待つ場合は、URLが確認ページに対応しているかをチェックする条件でコードをラップしてください。このアプローチにより、コードがサイト全体でトリガーされるのではなく、確認ページでのみ実行されることが保証されます。

**例:** ループを実行する前に特定の確認ページをターゲティングする

```javascript theme={null}
if (document.location.href.includes('/confirmation')) {
    let revenueLayer;
    Kameleoon.API.Core.runWhenConditionTrue(() => {
        revenueLayer = window.dataLayer && window.dataLayer.find(layer => layer.revenue);
        return revenueLayer;
    }, () => {
        Kameleoon.API.Goals.processConversion(goalId, revenueLayer.revenue);
    });
}
```

同様に、ページに要素が読み込まれるのを待つ場合は、その要素が表示されることが期待されていることを確認し、関連するページでのみスクリプトを実行してください。

```javascript theme={null}
if (document.location.href.includes('/subscription')) {
    Kameleoon.API.Core.runWhenElementPresent("#form", () => {
        // Add the rest of your logic here
    });
}
```

### 3. 視覚的な変更には JavaScript ではなく CSS を優先する(特にスクリプト内のバリエーションを扱う場合)

JavaScript の代わりに CSS を使用すると、レンダリングがより速く、よりスムーズになります。CSS は要素の非表示や変更、ブロックの入れ替え、スタイルやテキストの変更に活用できます。

### シングルページアプリケーション(SPA)の処理

シングルページアプリケーション(SPA)や動的に更新されるページ上で実験を実行する場合、特定の実装手順が必要です。従来のウェブサイトとは異なり、SPA はページ全体をリロードしないため、Kameleoon はコンテンツの更新がいつ起こるかを識別する必要があります。ベストプラクティスについては、シングルページアプリケーションでの実験のセットアップに関する [ガイド](/user-manual/experimentation/web-experimentation/advanced-experiment-types/set-up-experiment-single-page-app) を参照してください。

## セグメント / トリガー

最初のベストプラクティスは、ページの読み込み時に即座に利用可能なデータに基づいてターゲティングを行うことです。これには、ページのURL、ブラウザのタイプ、デバイスのタイプ、Cookie やローカルストレージに保存されているデータなどの情報が含まれます。

ターゲティングが即座にアクセスできないデータを必要とする場合は、効率的な実行を保証し、不要な遅延を避けるために以下のガイドラインに従ってください。

### 1. カスタム JavaScript 条件

この条件では、カスタム JavaScript を使用して訪問者をターゲティングできます。主に2つのオプションがあります:

\####- a. 条件をすぐにチェックする

このスクリプトは、DOM が完全に読み込まれる前は75ミリ秒ごとに、その後は250ミリ秒ごとに実行されます。デフォルトでは `undefined` を返し、明示的に `true`(訪問者を含める)または `false`(訪問者を除外する)を返すまでスクリプトはループ内で実行され続けます。不要なループを防ぐため、条件が最終的に `true` または `false` に解決されることを必ず確認してください。最適化された例は以下のとおりです:

```javascript theme={null}
if (window.dataLayer && window.dataLayer.some(layer => layer.pageType == "homepage")) return true; 

else if (window.dataLayer && window.dataLayer.some(layer => layer.pageType != "homepage")) return false;
```

\####- b. 条件を非同期で実行する

訪問者をターゲティングする前に外部のウェブサービスや API からの応答を待つ必要がある場合は、このスクリプトを使用します。応答を受け取ったら、setTargeting(true) または setTargeting(false) を呼び出します。以下のコードを参照してください。

<Note>
  * 特定の要素をターゲティングしたい場合は、代わりにネイティブの条件「ページ上の要素」を使用してください。
  * ページ上の情報を待ちたい場合は、上記の「条件をすぐにチェック」オプションを使用してください。
</Note>

```javascript theme={null}
const userId = localStorage.getItem("user_id"); 
if (!userId) {
   setTargeting(false);
}
// Example API endpoint - replace with your actual endpoint
const apiUrl = `https://api.example.com/check-segment?userId=${userId}`;

fetch(apiUrl, { method: "GET", headers: { "Content-Type": "application/json" } })
  .then(response => response.json())
  .then(data => {
    if (data && data.isInSegment) {
      setTargeting(true);
    } else {
      setTargeting(false);
    }
  })
  .catch(error => {
    setTargeting(false);
  });
```

### 2. カスタムイベント

カスタムイベントの使用は、訪問者をターゲティングする効果的でパッシブな方法です。条件を継続的に監視するのではなく、定義した特定のカスタムイベントをリッスンし、そのイベントが発生したときにターゲティングをトリガーします。このアプローチは、特に以下の2つの主要なシナリオで有用です:

#### シナリオ1: ターゲティングロジックが複雑な場合

すべてのロジックをターゲティング内の JavaScript 条件に直接埋め込むことは避けた方が良いです。代わりに、グローバルスクリプトでカスタムイベントを定義できます。たとえば、カート内に少なくとも3つの商品があり、合計金額が30ドルを超えるカートページの訪問者をターゲティングしたい場合、JavaScript セグメント条件内にすべてのロジックを書く代わりに、これらの条件が満たされたときにグローバルスクリプトでイベントをトリガーします。

#### シナリオ2: 複数のセグメントが類似のロジックを共有する場合

複数のセグメントが同じ条件、またはわずかに異なるバリエーションの同じ条件を必要とする場合、カスタムイベントを使用することで冗長なコードを防ぎ、保守性を高めます。

例: 異なるカート金額に基づいて訪問者をターゲティングする必要があります。複数のセグメントでロジックを重複させる代わりに、グローバルスクリプトで単一のスクリプトを定義し、各セグメントに対して異なるカスタムイベントをトリガーします:

```javascript theme={null}
if (document.location.href.includes('/cart')) {
    Kameleoon.API.Core.runWhenElementPresent("#cartContainer", ([cartContainer]) => {
        if (cartContainer.length >= 3) {
            const totalAmount = Number(cartContainer.querySelector('#totalAmount').innerText);
          
            if (totalAmount >= 90) 
                Kameleoon.API.Events.trigger("3ArticlesAbove90"); // Segment 1
            else if (totalAmount >= 60) 
                Kameleoon.API.Events.trigger("3ArticlesAbove60"); // Segment 2
            else if (totalAmount >= 30) 
                Kameleoon.API.Events.trigger("3ArticlesAbove30"); // Segment 3
        }
    });
}
```

### カスタムデータ

カスタムデータは、カスタムイベントと同様に、値を保存して再利用できるようにすることで重複コードを防ぐのに役立ちます。グローバルスクリプトや他のスクリプトでカスタムデータを定義し、セグメント内で利用できます。ただし、カスタムデータは2つの重要な点でカスタムイベントと異なります:

#### a. スコープオプション: 「ページ」、「訪問」、または「訪問者」

現在のページにのみ適用される **カスタムイベント** とは異なり、カスタムデータは複数のページとセッションにわたって持続できます:

* **訪問スコープ**: 訪問者のセッション全体で値を保持します。
* **訪問者スコープ**: Cookie ポリシーに応じて、最大365日間値を保存します。

たとえば、訪問者がログインしたらすべてのページでバナーを表示したい場合、訪問スコープでカスタムデータの値を "true" に設定できます。これにより、訪問者がログイン後のセッション中、すべてのページでバナーのターゲティングが維持されます。

#### b. 拡張された実験のインサイト

カスタムデータは、実験の結果ページでフィルターやブレイクダウンの基準として機能します。これにより、より深いインサイトが得られ、訪問者の行動をより効果的に分析できます。

セグメントビルダーで利用可能なすべてのターゲティング条件を確認するには、この [ドキュメント](/user-manual/assets/segments/create-a-segment) を参照してください。
