このページでは

For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.

Contentful

Amplitude 実験用のContentfulプラグインを使用すると、Contentfulでコンテンツのバリエーションを作成したり、実験を使用して各ユーザーがどのバリエーションを表示するかを制御したり、それらのバリエーションのパフォーマンスを追跡したりできます。

機能

  • Amplitude 実験でA/Bテストを実行し、Contentfulでコンテンツを作成します。
  • Amplitude 実験からプロパティを読み取り(5秒ごとに更新されます)、それらのプロパティを中心にコンテンツを作成します。

要件

このプラグインを使用するには、次のものが用意されていることを確認してください。

  • Amplitude 実験が有効になっているAmplitudeプランへのアクセス。
  • Amplitude OrgのURL値。この値は、Amplitudeへのアクセスに使用するURLに表示されます:https://app.amplitude.com/experiment/<ORG_URL>/dashboard。
  • Management APIキー。これは実験のサイドバーにあります。

インストールと使用

ContentfulとAmplitudeで以下の手順を実行して、Amplitude 実験用のContentfulプラグインを追加して有効にします。

プラグインをインストールする
  1. Contentfulマーケットプレイスからプラグインをインストールします。
  2. プラグイン設定で、実験で作成したデータセンター、組織URL、およびManagement APIキーを入力します。
  3. 選択した環境にインストールをクリックします。
  4. 保存をクリックしてプラグインの設定を完了します。

プラグインを有効にすると、Variant Containerコンテンツモデルがコンテンツモデルタブに表示されます。

コンテンツモデルにバリアントコンテナを追加する

ContentfulのバリアントコンテナはAmplitude 実験と連携して、各ユーザーがどの実験バリアントを表示できるかを決定します。

最良の結果を得るためには、Amplitudeは実験を行う際に「参照」コンテンツタイプを使用することをお勧めします。

バリアントコンテナを追加するには
  1. バリアントコンテナを追加するページのコンテンツモデルを開きます。
  2. **「フィールドを追加」**をクリックします。[参照]フィールドを選択します。
  3. フィールドの名前を入力します。 最良の結果を得るには、フィールドの目的に合った名前を入力してください。 たとえば、Hero BannerまたはDemo CTAです。
  4. タイプとして1つの参照を選択します。
  5. 追加して設定をクリックします。
  6. フィールド設定の「名前とフィールドID」タブで、指定されたエントリタイプのみを受け入れるを選択し、バリアントコンテナを選択します。この設定により、Contentfulがページコンテンツを配信する場合に Contentful API レスポンスの一貫性が保たれます。
  7. 確認をクリックしてフィールドを作成し、保存をクリックしてコンテンツモデルを更新します。

実験にコンテンツを追加する

バリアントコンテナと参照フィールドを設定したら、実験を追加したいページを開きます。

実験にコンテンツを追加するには
  1. コンテンツエディタで、ページを選択します。
  2. 前の手順で作成したフィールドを見つけ、関連付けられた**「コンテンツを追加」**セレクターをクリックします。
  3. 追加するコンテンツとして「バリアントコンテナ」を選択します。
  4. フィールド設定で、実験のフラグキーを入力します。 [フラグキー]フィールドには、入力時に一致するキーが表示されます。
  5. フラグキーを選択すると、そのキーに関連付けられたすべてのバリアントが「バリアント」セクションに表示されます。
  6. 各バリアントに対して、[既存のエントリをリンクする]または[新しいコンテンツタイプを作成する]を選択して、バリアントにデータを入力します。
  7. 「公開」をクリックしてバリアントコンテナを公開します。
  8. 公開をクリックして、実験を有効にした状態で更新されたページを公開します。

フロントエンドとの統合

Contentful はユーザーがページをリクエストすると JSON を返します:

json
{
  "__typename": "PageLanding",
  "sys": {
    "id": "2cayfg7wVF5WezADCHgSgL",
    "spaceId": "4y4crvvoco9a"
  },
  "internalName": "Homepage",
  "heroBanner": {
    "__typename": "VariationContainer",
    "experiment": {
      "id": "183980",
      "key": "contentful-hero-banner",
      "name": "contentful-hero-banner",
      "tags": [],
      "state": "running",
      "deleted": false,
      "enabled": true,
      "endDate": null,
      "decision": null,
      "variants": [
        {
          "key": "control"
        },
        {
          "key": "treatment"
        }
      ],
      "projectId": "289220",
      "startDate": "2024-02-22",
      "deployments": ["14"],
      "description": "",
      "bucketingKey": "amplitude_id",
      "bucketingSalt": "28fWNw1M",
      "bucketingUnit": "User",
      "decisionReason": null,
      "evaluationMode": "remote",
      "experimentType": "hypothesis-testing",
      "rolloutWeights": {
        "control": 1,
        "treatment": 1
      },
      "targetSegments": [],
      "stickyBucketing": false,
      "rolledOutVariant": null,
      "rolloutPercentage": 0
    },
    "experimentId": "contentful-hero-banner",
    "meta": {
      "control": "6rmYK8YKYtTkKcFRY9Pf2w",
      "treatment": "kwDjI2f2vKE2GvQoeqq1d"
    },
    "variationsCollection": {
      "items": [
        {
          "__typename": "Hero",
          "sys": {
            "id": "6rmYK8YKYtTkKcFRY9Pf2w",
            "spaceId": "4y4crvvoco9a"
          },
          "preHeadline": "Organic Products",
          "headline": "100% Fresh Food",
          "cta": "Shop Now",
          "description": "Whatever you want from your local stores, brought right to your door. \t\t\t\t\t\t\t",
          "image": {
            "__typename": "Asset",
            "sys": {
              "id": "6PkraSxWWd96AU6FTYVssd"
            },
            "title": "Fresh food",
            "description": "",
            "width": 2560,
            "height": 960,
            "url": "https://images.ctfassets.net/4y4crvvoco9a/6PkraSxWWd96AU6FTYVssd/69b8d7f7cabb9f578097d50f2bf8aa70/Hero-3-1-scaled.jpg",
            "contentType": "image/jpeg"
          }
        },
        {
          "__typename": "Hero",
          "sys": {
            "id": "kwDjI2f2vKE2GvQoeqq1d",
            "spaceId": "4y4crvvoco9a"
          },
          "preHeadline": "Exclusive Offer",
          "headline": "Loyalty Program",
          "cta": "Get Free Shipping",
          "description": "We missed you! Finish your order today and get free shipping when you join our loyalty program.",
          "image": {
            "__typename": "Asset",
            "sys": {
              "id": "6WFOK0460CwrW7aChl1QjM"
            },
            "title": "Loyalty Green",
            "description": "",
            "width": 1920,
            "height": 720,
            "url": "https://images.ctfassets.net/4y4crvvoco9a/6WFOK0460CwrW7aChl1QjM/e52fb2129b848203f6006ff9881309d9/Hero-_-loyalty-green.jpg",
            "contentType": "image/jpeg"
          }
        }
      ]
    }
  }
}

experimentオブジェクトには、実験に関する有用なメタデータが含まれています。フロントエンドをレンダリングして実験を含めるには、metaオブジェクトとvariationsCollectionオブジェクトを使用します。Amplitude 実験はバリアント識別子を渡し、それをmetaオブジェクト内のオプションと照合します。バリアントを設定した後、次のことが可能です:

  • variationsCollectionオブジェクト内のアイテムを反復処理し、一致するIDを持つバリエーションを表示します。
  • 配列の検索を避けるために、バリアントIDを使用してContentfulに直接呼び出してください。

詳細については、次の React と TypeScript の例を参照してください。

typescript
import React, { useEffect, useState } from "react";
import { Experiment } from "@amplitude/experiment-js-client";
import sdk from "contentful-sdk";
// --- Types (adjust to your schema) ---
type Hero = {
  __typename: "Hero";
  sys: { id: string };
  // ...other fields you render
};
type HeroBanner = {
  experimentId?: string; // key you use in Amplitude Experiment
  meta?: Record<string, string>; // maps variant key -> variation id
  variationsCollection?: { items: Array<Hero | null | undefined> };
};
// --- Experiment init ---
const CLIENT_KEY =
  process.env.NEXT_PUBLIC_AMPLITUDE_EXPERIMENT_CLIENT_KEY ?? "";
export const experiment = Experiment.initialize(CLIENT_KEY, {
  // Only enable verbose logging in dev if you like:
  debug: process.env.NODE_ENV !== "production",
});
// --- Component hook snippet ---
export function useHeroVariant(userId: string | undefined) {
  const [hero, setHero] = useState<Hero | null>(null);
  useEffect(() => {
    // Skip until we have a user id
    if (!userId) return;
    let isMounted = true;
    (async () => {
      try {
        // 1) Fetch variants for this user
        await experiment.fetch({ user_id: userId });
        // 2) Load the banner/experiment mapping from Contentful
        const heroBanner = await sdk.getEntry<HeroBanner>("ENTRY_ID_HERE");
        if (!heroBanner) return;
        // 3) Resolve the variant key from the experiment
        const experimentKey = heroBanner.experimentId ?? "control";
        const { value: variantKey } = experiment.variant(experimentKey);
        if (!variantKey) return;
        // 4) Map the variant key -> variation id through Contentful metadata
        const variationId = heroBanner.meta?.[variantKey];
        if (!variationId) return;
        // 5) Find the matching Hero item
        const match =
          heroBanner.variationsCollection?.items.find(
            (item): item is Hero =>
              !!item &&
              item.__typename === "Hero" &&
              item.sys?.id === variationId,
          ) ?? null;
        if (isMounted) setHero(match);
      } catch (err) {
        // Consider forwarding to your logger
        console.error("Failed to resolve hero variant", err);
        if (isMounted) setHero(null);
      }
    })();
    return () => {
      isMounted = false;
    };
  }, [userId]); // Note: don't include heroBanner (it's local) or setHero
  return hero;
}

ユーザーがexperiment.variant()の戻り値としてoffを受け取るケースも考慮にいれます。

これは役に立ちましたか?