🚀

レア「配信の分析」機能のご紹介 — 売れるLINE配信の作り方

に公開

※この記事は音声で構成を伝え大枠をChatGPTに作ってもらい
必要なサンプルコード部分をDevinに作ってもらいました。

レア「配信の分析」機能の紹介 — 売れるLINE配信の作り方

LINE×ECにおいてのLINE配信は、販売促進の手段として非常に有効ですが
どのような配信を送れば売上が伸びるのかを把握するのは難しいです。
https://lea-market.com/

レアではLINE配信の分析が自動で出来る。

なぜ分析が必要か

LINEは到達率・反応率が高い一方で、配信→開封→来訪→カート→注文と最終的に売り上げにつながるゴールまでにどこで離脱が起きているかを把握しなければ、改善の手がかりは得られません。レアの分析機能は、この一連のプロセスをファネル(行動)を分析し、改善の仮説検証を高速化します。


全体像:配信後の基本フロー

  1. 配信(セグメント送信)
  2. 開封(メッセージが閲覧されたか)
  3. ショップアクセス(LP/商品ページへの着地)
  4. カート追加
  5. 注文(購入)

レアはこの各段階を計測し、配信単位・セグメント単位・期間/キャンペーン単位での比較を可能にします。


計測アーキテクチャの概要

レアでは、配信の効果測定を以下の2つの仕組みで実現しています。

開封率の計測

LINE公式APIを利用して開封イベントを取得・集計します。

アクセス〜注文の計測

レアが配信内URLに計測パラメータを付与し、到達先(ショップ/LP)側で発生する以下のイベントをUserActionLogとして記録します。

  • ページアクセス
  • カート追加
  • レジへ進む
  • 注文

これらを時系列・ユーザー・配信IDなどのキーで紐づけ、集計します。


データモデル:配信とユーザー行動の記録

Delivery(配信)

配信は以下のような構造でFirestoreに保存されます。

export interface Delivery extends AppBase {
  templateId: string | null          // 使用したテンプレートID
  userSearchParams: UserSearchParams // セグメント条件
  isReservation: IsReservationType   // 即時配信 or 予約配信
  sendCount: number | null           // 実際に配信した人数
  deliveryAt: firebase.firestore.Timestamp | null // 配信日時
}

配信は /apps/{adminUserUid}/deliveries/{deliveryUid} に保存され、各配信には一意のIDが付与されます。このIDが後のトラッキングに使用されます。

UserActionLog(ユーザー行動ログ)

ユーザーの全ての行動は UserActionLog として記録されます。

export type UserActionType =
  | 'access'        // ページアクセス
  | 'cart'          // カート追加
  | 'cashRegister'  // レジに進む
  | 'order'         // 注文

export interface UserActionLogBase extends Base, CampaignSourceQuery {
  type: UserActionType
  adminUserUid: string
  userId: string // ユーザーID
}

// キャンペーンソースの追跡
export interface CampaignSourceQuery {
  campaignSourceType: SourceType | null // 'delivery' | 'step' | 'richMenu' など
  campaignSourceId: string | null       // 配信IDなどが入る
}

各行動タイプごとに専用のインターフェースが定義されています。

アクセスログ

export interface AccessAction extends UserActionLogBase {
  type: 'access'
  pagePath: string             // 例: "/campaigns/mmvM0cg17qCepV8TFRoP"
  pageMatchedPath: string | null // 例: "/campaigns/:campaignUid"
  fromPath: string | null      // 前のページのURL
  fromMatchedPath: string | null
}

カートログ

export interface cartAction extends UserActionLogBase {
  type: 'cart'
  cartUid: string
  cartItem: UserCart // カートに追加された商品情報
}

注文ログ

export interface OrderAction extends UserActionLogBase {
  type: 'order'
  orderUid: string
  orderItem: Order | OrderBanking // 注文の詳細情報
}

開封率の計測(LINE公式APIによる取得)

LINE Insight APIの活用

LINE公式アカウントが提供するInsight APIを使用して、配信メッセージの開封状況を取得します。

export interface LineInsight {
  overview: {
    uniqueImpression: number | null        // ユニーク開封数
    uniqueClick: number | null             // ユニーククリック数
    uniqueMediaPlayed: number | null       // メディア再生数
    uniqueMediaPlayed100Percent: number | null // 最後まで再生
  }
  messages: [{
    seq: number
    impression: number | null              // 開封数
    mediaPlayed: number | null
    mediaPlayed25Percent: number | null
    mediaPlayed50Percent: number | null
    mediaPlayed75Percent: number | null
    mediaPlayed100Percent: number | null
    uniqueMediaPlayed: number | null
    uniqueMediaPlayed25Percent: number | null
    uniqueMediaPlayed50Percent: number | null
    uniqueMediaPlayed75Percent: number | null
    uniqueMediaPlayed100Percent: number | null
  }]
  clicks: {
    seq: number
    url: string
    click: number
    uniqueClick: number | null
    uniqueClickOfRequest: number | null
  }[]
}

PUSHメッセージ送信時のインサイトID指定

配信メッセージを送信する際、LINE APIの customAggregationUnits パラメータに配信IDを指定することで、後からインサイトAPIで開封率を取得できるようにします。

export const lmcMessagePush = async (
  botId: string,
  toUserId: string,
  messages: Message[] | Message,
  lineModuleChannelAccessToken: string,
  showQuickReply: boolean,
  customAggregationUnits?: string  // 配信IDを指定
): Promise<void> => {
  try {
    const url = 'https://api.line.me/v2/bot/message/push'
    const headers = {
      'content-type': 'application/json',
      'X-Line-Bot-Id': botId,
      Authorization: `Bearer ${lineModuleChannelAccessToken}`
    }

    if (!Array.isArray(messages)) {
      messages = [messages]
    }
    if (showQuickReply) {
      messages[messages.length - 1].quickReply = quickReply
    }

    // customAggregationUnitsを指定することで、後からインサイトAPIで開封率を取得可能
    const body = {
      to: toUserId,
      messages,
      customAggregationUnits: customAggregationUnits ? [customAggregationUnits] : undefined
    }
    await axios.post(url, body, { headers })
  } catch (err) {
    throw new Error(`lmcMessagePush - ${errorHandler(err)}`)
  }
}

開封データ取得の実装

配信時に指定した customAggregationUnits(配信ID)を使って、後から開封率などのインサイトデータを取得します。

export const getLineInsight = async (
  botId: string,
  unitId: string,        // 配信ID(customAggregationUnit)
  from: string,          // 集計開始日 "YYYY-MM-DD"
  to: string,            // 集計終了日 "YYYY-MM-DD"
  lineModuleChannelAccessToken: string
): Promise<LineInsight | null> => {
  const url = 'https://api.line.me/v2/bot/insight/message/event/aggregation'
  const params = {
    customAggregationUnit: unitId,  // 配信時に指定したIDでフィルタリング
    from,
    to
  }
  const headers = {
    'content-type': 'application/json',
    'X-Line-Bot-Id': botId,
    Authorization: `Bearer ${lineModuleChannelAccessToken}`
  }

  try {
    const { data } = await axios.get(url, {
      params,
      headers
    })
    return data
  } catch (err) {
    console.error(err)
    return null
  }
}

このように、配信時に customAggregationUnits として配信IDを指定し、後からそのIDを使ってインサイトAPIを呼び出すことで、特定の配信の開封率を正確に追跡できます。


アクセス〜注文の計測(ログベース)

集計したログをBigQueryで計算し結果を表示

おまけ

作成した配信分析機能を使って
効果のある配信を検証した結果がわかったので
興味がある人は見てみてください

https://x.com/haruya_em/status/1956372311197864184

Discussion