メインコンテンツへスキップ

概要

このチュートリアルでは、一般的な予約ワークフローを設定します:
  • ユーザーが予約を完了した後に予約確認メールを送信します。
  • ユーザーが予約を開始したが時間内に完了しなかった場合に回復メールを送信します。
最終的に、以下を持つことになります:
  • 2つのカスタムイベント(booking_startedbooking_complete
  • 完了対放棄で分岐する1つのJourney
  • 確認詳細用の予約Data Feed
  • 回復インセンティブ用のオプションのクーポンData Feed
このガイドはOneSignalの設定に焦点を当てています。予約システムとバックエンドは任意の言語またはフレームワークで実装できます。

セットアップフロー

  1. アプリがbooking_started カスタムイベントを追跡します。
  2. これによりユーザーがJourneyに入ります。
  3. Journeyはbooking_completeイベントを待ち、時間内に受信されない場合、フォローアップリマインダーを送信します。
  4. 予約が完了すると、OneSignalは送信時に予約Data Feedを呼び出し、最新の予約詳細を含む確認メールを送信します。
  5. 予約が待機ウィンドウ内で完了しない場合、Journeyは有効期限パスに従い、回復メールを送信します。

セットアップ

前提条件

開始する前に、以下を確認してください:
  • メール チャネルが有効化されたOneSignalアプリ
  • 予約および/またはクーポンデータをJSONで返すことができるバックエンドエンドポイント
  • アプリ、バックエンド、OneSignalのExternal ID間で共有される安定したユーザー識別子
  • カスタムイベントへのアクセス

1. 予約イベントの追跡

以下のカスタムイベントを追跡します。これらはアプリ(SDKを使用)またはバックエンド(REST APIを使用)から送信できます。 イベント名:
  • booking_started — ユーザーが予約フローを開始したとき
  • booking_complete — 予約が正常に完了したとき
モバイルSDKおよび/またはWeb SDKtrackEvent()メソッドを使用して、アプリ/ウェブサイトから直接カスタムイベントを送信します。
OneSignal.User.trackEvent("booking_started");
OneSignal.User.trackEvent("booking_complete");
イベントの追跡時とバックエンドからデータを返すときに同じユーザー識別を使用してください。不一致のIDは、パーソナライゼーションが欠落する最も一般的な原因です。

2. Data Feedエイリアスの作成

OneSignalで、設定 > Data Feedsに移動し、以下のエイリアスを作成します。 予約Data Feed: このフィードを使用して、送信時に最新の予約詳細を取得します。
  • エイリアス: booking_data
  • メソッド: GET
  • URL:
エンドポイント例
https://your-domain.com/datafeed/booking?user_id={{subscription.external_id}}
レスポンス例:
JSON
{
  "first_name": "Sam",
  "last_booking": {
    "service_type": "相談",
    "booking_date": "2026年1月22日",
    "booking_time": "14:00",
    "price": 45
  }
}
クーポンData Feed(オプション): 回復メールにクーポンコードを含めたい場合は、このオプションのフィードを使用します。
  • エイリアス: coupon
  • メソッド: GET
  • URL:
エンドポイント例
https://your-domain.com/datafeed/coupon?user_id={{subscription.external_id}}
レスポンス例:
JSON
{
  "first_name": "Sam",
  "code": "PROMO8F3K2",
  "discount_text": "10%",
  "expires_in_hours": 2,
  "deep_link": "https://your-domain.com/checkout?coupon=PROMO8F3K2"
}
Data Feedエンドポイントを保護してください。本番環境では、リクエストヘッダーでAPIキー(例:x-api-key)を送信し、URLにシークレットを埋め込む代わりに設定 > Data Feedsでそのヘッダーを設定してください。

3. メールテンプレートの作成

予約確認メール:

件名:
ご予約の詳細
本文:
{{ data_feed.booking_data.first_name | default: "お客様" }}さん、こんにちは

ご予約ありがとうございます!ご予約の詳細は以下の通りです:

サービス:{{ data_feed.booking_data.last_booking.service_type }}
日付:{{ data_feed.booking_data.last_booking.booking_date }}
時間:{{ data_feed.booking_data.last_booking.booking_time }}
料金:{{ data_feed.booking_data.last_booking.price }}

お会いできるのを楽しみにしています!

予約回復メール

件名:
ご予約を完了してお得に
本文:
{{ data_feed.coupon.first_name | default: "お客様" }}さん、こんにちは

今後{{ data_feed.coupon.expires_in_hours }}時間以内にご予約を完了すると、
このコードで{{ data_feed.coupon.discount_text }}オフになります:

{{ data_feed.coupon.code }}

こちらでご利用ください:
{{ data_feed.coupon.deep_link }}
Data Feedフィールドが欠落している場合に空白コンテンツを防ぐため、Liquidには常にdefaultフィルターを含めてください。

4. Journeyの構築

  1. OneSignalで、メッセージ > Journeys > Journeyを作成に移動
  2. エントリートリガーを以下に設定:
    • カスタムイベント: booking_started
  3. Wait Untilステップを追加:
    • 条件: カスタムイベントが発生
    • イベント名: booking_complete
    • 最大待機時間: 10分
    • 有効期限パスを有効化
  4. ブランチを設定:
    • 完了: 予約確認メールを送信
      • Data Feed: booking_data
    • 期限切れ: 回復メールを送信
      • Data Feed: coupon
有効期限ブランチにより、アプリで追加のロジックなしに放棄を処理できます。詳細は以下を参照:

5. テストと検証

イベントの確認

アプリまたはバックエンドからカスタムイベントをトリガーして確認します。 OneSignalで、Analytics > カスタムイベントに移動し、以下が表示されることを確認:
  • External IDに対してbooking_startedイベントが表示される
  • External IDに対してbooking_completeイベントが表示される

Data Feedの確認

既知のユーザーIDを使用してData Feedエンドポイントを手動で呼び出し、以下を確認:
  • 200レスポンスが返される
  • すべての予期されるフィールドが存在する

メールの確認

Journeyエディターからテストメッセージを送信し、以下を確認:
  • 予約メールに実際の予約詳細が含まれている
  • 回復メールに有効なクーポンが含まれている
  • Liquid変数が空でレンダリングされていない
パーソナライゼーションが欠落している場合は、Data FeedリクエストのユーザーIDがJourneyをトリガーしたユーザーと一致することを確認してください。

例:Data Feed実装

この例では、予約確認および回復Data Feed用の最小限のExpress実装を示します。JSONレスポンス形式がメールテンプレートと一致する限り、バックエンド言語、フレームワーク、データソースは異なっても構いません。

予約Data Feedの例

import express from "express";

const app = express();

function dataFeedAuth(req, res, next) {
  if (req.headers["x-api-key"] !== process.env.DATAFEED_API_KEY) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  next();
}

app.get("/datafeed/booking", dataFeedAuth, async (req, res) => {
  const { user_id } = req.query;

  if (!user_id) {
    return res.status(400).json({ error: "Missing user_id" });
  }

  const booking = await getLatestBookingForUser(user_id);

  if (!booking) {
    return res.status(404).json({ error: "No booking found" });
  }

  res.json({
    first_name: booking.first_name,
    last_booking: {
      service_type: booking.service_type,
      booking_date: booking.booking_date,
      booking_time: booking.booking_time,
      price: booking.price
    }
  });
});

クーポンData Feedの例

app.get("/datafeed/coupon", dataFeedAuth, async (req, res) => {
  const { user_id } = req.query;

  if (!user_id) {
    return res.status(400).json({ error: "Missing user_id" });
  }

  const coupon = await generateCouponForUser(user_id);

  res.json({
    first_name: coupon.first_name,
    code: coupon.code,
    discount_text: coupon.discount_text,
    expires_in_hours: coupon.expires_in_hours,
    deep_link: coupon.deep_link
  });
});

実装ガイドライン

  • レスポンスを高速に保つ(Data Feedは送信時に呼び出される)
  • 常に予測可能なJSON構造を返す
  • データが存在しない場合は404を使用
  • リクエストヘッダー経由で送信されるAPIキーでエンドポイントを保護

よくある問題

メールに空の値が表示される

  • Data Feedが404を返した
  • JSONレスポンスでフィールド名が変更された
  • ユーザー識別の不一致

Journeyが分岐しない

  • booking_completeイベントが追跡されていない
  • イベント名の不一致(大文字小文字を区別)
  • 待機ウィンドウの外でイベントが発生

Data Feedが401または403を返す

  • APIキーが欠落または無効
  • Data Feed設定でヘッダーが設定されていない

次のステップ

  • より高度なJourney条件のためにイベントプロパティ(サービスタイプ、価格)を追加
  • プッシュまたはSMSリマインダーなど、追加の回復ステップを追加
  • 重複する回復メッセージを防ぐためにJourney出口ルールを使用