SKAd Network コンバージョン値スキーマで収益バケットを計算する

1. はじめに

始める前に

iOS アプリのデベロッパーの方は、iOS 14.5 以降でのプライバシーの更新をご存じかもしれません。Apple では、インストール後の有意なコンバージョン アクションを測定するために、ユーザーのプライバシーを尊重しながら広告キャンペーンの成果を測定できる SKAd Network API を提供しています。SKAd Network を活用してキャンペーンに関する有意義な分析情報を得るための最適な方法を、ビジネスニーズに基づいて見極めることができます。この Codelab では、BigQuery の GA4F データを活用して、アプリのインストール後の収益をバケットにグループ化し、App Attribution Partner とともに設定するためのサンプル手法を確認します。この Codelab では収益ベースのアプローチを使用しますが、SKAN の測定にイベントベースまたはファネル ベースのアプローチを使用することもできます。詳しくは、こちらのヘルプセンターをご覧ください。これは一例であり、Google が公式に推奨するものではありません。特定のビジネスニーズに基づいて独自のスキーマを設計できる

説明する内容

  • BigQuery で GA4F データを探索する
  • 0 ~ 2 日以内にコンバージョンに至ったユーザーの収益データを確認できます
  • 収益データをバケットにまとめる
  • 各バケットでのユーザー分布を把握する
  • Appsflyer SKAN コンバージョン Studio でバケットを実装する

前提条件

2. BigQuery Export へのアクセス

[Project Settings] > [統合 >BigQuery。最初に切り替えを有効にする必要があります。有効にしてからデータセットが使用可能になるまでに 48 時間ほどかかります。以下のリンクをクリックすると、BigQuery に移動します。

1aa4e20bfd3419d1.png

クエリを実行する

BigQuery にログインしたら、生成された日次テーブルが表示されます。以下のスクリーンショットの例では、64 個の日次テーブルが表示されているため、エクスポートは 64 日間実行されています。初めてアクセスする場合、前日のデータが格納された日次テーブルが 1 つだけ表示される場合があります。右側にはテーブル スキーマが表示されます。各フィールドの詳細については、こちらをご覧ください。

クエリの作成を開始するには、[クエリ >新しいタブ

42ba59ec655c5d1b.png

その後、新しいタブでサンプルクエリを実行してみてください

70ef90d32b7cd7f1.png

3. 収益データを分析する

インストール データの取得

収益バケットの構築を始めるには、まず過去 24 ~ 72 時間以内にアプリをインストールしたユーザーのデータを確認する必要があります。SKAd Network 4.0 では 0 ~ 2 日で、SKAd Network 3.5 では 24 時間でデータを表示できます。(App Attribution Partner の機能によっては、このアクティビティ期間は通常 72 時間以内まで変更できます)。ユーザーがアプリをインストールして初めて開くと、SDK によって first_open イベントが発生し、BigQuery に記録されます。

BigQuery で使用できる識別子は user_pseudo_id(アプリ インスタンス ID とも呼ばれます)であるため、以下のクエリを使用してこれらのユーザーを見つけることができます。

SELECT
  user_pseudo_id,
  event_name,
  event_date,
  event_timestamp
FROM `project_name.dataset_name.events_2023*`
WHERE
  event_name = 'first_open'
  AND platform = 'IOS'

このクエリに関する注意点

  • テーブル名を、アナリティクスのエクスポートしたテーブルに置き換えてください。ワイルドカード を使用すると、複数の日次テーブルに対してクエリを実行できます。たとえば、2023 年* と指定すると、2023 年はすべてのデータを対象にクエリが実行されます
  • ユーザー数が多い場合は、過去 30 日間のみをクエリして処理を高速化することもできます。
  • プラットフォーム =「IOS」でフィルタします。Firebase プロジェクトに複数の iOS アプリがある場合は、app_info.firebase_app_id のフィルタを追加して特定のアプリのデータを取得することもできます。

収益データの取得

では、ユーザーの収益を調べるクエリを見てみましょう。この場合、収益イベントは in_app_purchase と ad_impression であるものとします。in_app_purchase の収益は event_value_usd で、ad_impression の収益はイベント パラメータの value パラメータで確認できます。BigQuery のイベント パラメータについてよく知らない場合は、こちらで定義を確認することをおすすめします。また、event_params から値を抽出する方法も取り上げている Google の公式リファレンスでこのサンプルクエリを試すこともできます。

SELECT
  user_pseudo_id,
  event_name,
  EXTRACT(date FROM Parse_datetime('%Y%m%d', event_date)) AS event_date,
  (
    SELECT COALESCE(value.int_value, value.float_value, value.double_value, NULL)
    FROM UNNEST(event_params)
    WHERE
      KEY = 'value'
      AND event_name = 'ad_impression'
  ) AS ad_funded_revenue,
  (
    SELECT value.string_value
    FROM UNNEST(event_params)
    WHERE
      KEY = 'currency'
      AND event_name = 'ad_impression'
  ) AS ad_revenue_currency,
  (
    CASE
      WHEN event_name = 'in_app_purchase' THEN event_value_in_usd
      ELSE 0
      END) AS iap_revenue_usd,
FROM `project_name.dataset_name.events_2023*`
WHERE
  platform = 'IOS'
  AND event_name IN (
    'in_app_purchase',
    'ad_impression')

ここでクエリの内容を理解しましょう。このように

  • WHERE 句で収益イベントのみをフィルタします。目的の収益イベントのみに着目します。前回と同様に、iOS データを探します。
  • SELECT 句で、広告収益イベント(ad_impression)と通貨の値を取得し、イベントが in_app_purchase のときに event_value_in_usd を取得しています
  • 複数の通貨を送信する場合は、まずこの分析で 1 つの通貨に合わせる必要があります。この例では、広告収入を得るための通貨も米ドルであると仮定します。

出力は次のようになります(ここでは user_pseudo_id の列は削除しています)。

1e1e6943e4b3a6d8.png

このデータを組み合わせる

ここまでで、2 つのクエリを実行しました。1 つはアプリをインストールして開いたユーザーのデータを調べるクエリ、もう 1 つはそれらのユーザーの収益を確認するクエリです。ここまで、SKAd Network の制限について説明しました。アトリビューション期間を利用できるのは、インストール後 0 ~ 2 日間のみです。そのため、インストールと収益のイベントのタイムスタンプをチェックし、その期間内に発生した場合にのみ情報を取得する必要があります。では、アプリのインストールを 2 日経過した投稿ごとの総収益を算出するクエリに結合してみましょう。

#creating the install table
WITH
  install_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_date,
      event_timestamp
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      event_name = 'first_open'
      AND platform = 'IOS'
  ),
  #creating the revenue table
  revenue_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_timestamp,
      EXTRACT(date FROM Parse_datetime('%Y%m%d', event_date)) AS event_date,
      (
        SELECT COALESCE(value.int_value, value.float_value, value.double_value, NULL)
        FROM UNNEST(event_params)
        WHERE
          KEY = 'value'
          AND event_name = 'ad_impression'
      ) AS ad_funded_revenue,
      (
        SELECT value.string_value
        FROM UNNEST(event_params)
        WHERE
          KEY = 'currency'
          AND event_name = 'ad_impression'
      ) AS ad_revenue_currency,
      (
        CASE
          WHEN event_name = 'in_app_purchase' THEN event_value_in_usd
          ELSE 0
          END) AS iap_revenue_usd,
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      platform = 'IOS'
      AND event_name IN (
        'in_app_purchase',
        'ad_impression')
  )
SELECT
  it.user_pseudo_id AS user_pseudo_id,
  #combine ad revenue and IAP revenue, assuming both are in same currency
  sum(ifnull(rt.iap_revenue_usd,0) + ifnull(rt.ad_funded_revenue,0)) AS total_revenue,
FROM install_table it
INNER JOIN revenue_table rt
  ON it.user_pseudo_id = rt.user_pseudo_id
WHERE
  rt.event_timestamp >= it.event_timestamp
  AND rt.event_timestamp
    <= it.event_timestamp + 86400000000 * 2  #added 86400 000 millisecond as 24 hours, taking for 2 days later
GROUP BY 1

このクエリは、user_pseudo_id フィールドのインストール データと収益データの結合を試行するだけなので、タイムスタンプが 2 日以内であることを確認する必要があります。SKAd Network 3.5 を使用している場合、デフォルトは 24 時間です。1 日分のデータのみが含まれるように条件を変更することもできます

収益をバケットに分類する

前のクエリの後に、user_pseudo_id と総収益

2c1986b93e937d19.png

これを、コンバージョン値の範囲に使用できる複数のバケットに分ける必要があります。この目的のために、BigQuery の approx_quantiles 関数を使用します。この関数はこれらの範囲を自動的に作成します。この例では、5 つの範囲を作成するものと仮定します。そのため、SELECT approx_quantiles(total_revenue, 5) AS バケットを使用できます。

それでは、これをクエリ全体に組み込みましょう。

#creating the install table
WITH
  install_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_date,
      event_timestamp
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      event_name = 'first_open'
      AND platform = 'IOS'
  ),
  #creating the revenue table
  revenue_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_timestamp,
      EXTRACT(date FROM Parse_datetime('%Y%m%d', event_date)) AS event_date,
      (
        SELECT COALESCE(value.int_value, value.float_value, value.double_value, NULL)
        FROM UNNEST(event_params)
        WHERE
          KEY = 'value'
          AND event_name = 'ad_impression'
      ) AS ad_funded_revenue,
      (
        SELECT value.string_value
        FROM UNNEST(event_params)
        WHERE
          KEY = 'currency'
          AND event_name = 'ad_impression'
      ) AS ad_revenue_currency,
      (
        CASE
          WHEN event_name = 'in_app_purchase' THEN event_value_in_usd
          ELSE 0
          END) AS iap_revenue_usd,
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      platform = 'IOS'
      AND event_name IN (
        'in_app_purchase',
        'ad_impression')
  ),
  total_revenue_table AS (
    SELECT
      it.user_pseudo_id AS user_pseudo_id,
      #combine ad revenue and IAP revenue, assuming both are in same currency
      sum(ifnull(rt.iap_revenue_usd,0) + ifnull(rt.ad_funded_revenue,0)) AS total_revenue,
    FROM install_table it
    INNER JOIN revenue_table rt
      ON it.user_pseudo_id = rt.user_pseudo_id
    WHERE
      rt.event_timestamp >= it.event_timestamp
      AND rt.event_timestamp
        <= it.event_timestamp + 86400000000 * 2  #added 86400 000 millisecond as 24 hours
    GROUP BY 1
  )
SELECT approx_quantiles(total_revenue, 5) AS buckets FROM total_revenue_table

このクエリでは、収益を 5 つのバケットに分割し、BigQuery は一貫したパーセンタイル分布の維持を試みます。

ba46f5d993449948.png

これらのバケットでユーザー分布を分析する

各バケットでのユーザーの分布を把握する場合は、このステップは省略できます。この例では、前のクエリで返されたバケット範囲は次のようになります。

  • 0.1
  • 0.5
  • 2
  • 2.5
  • 5 [最後の値は範囲構成で使用しない]

最後の範囲については、最後のバケット 5 を無視します。これが通常は最大値であり、2.5 を最後の範囲と見なすことができます。これは、アプリ アトリビューションのプロバイダでは広告費用対効果の計算に範囲の平均を使用することが多いため、計算の均一性を高めるために外れ値は除外する必要があるためです。

各バケットの 1 日あたりのユーザー数を把握できるように、すべての範囲の日付ごとにユーザー数を確認します。バケットの値を実際のデータに置き換えると、このクエリは次のようになります。

#creating the install table
WITH
  install_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_date,
      event_timestamp
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      event_name = 'first_open'
      AND platform = 'IOS'
  ),
  #creating the revenue table
  revenue_table AS (
    SELECT
      user_pseudo_id,
      event_name,
      event_timestamp,
      EXTRACT(date FROM Parse_datetime('%Y%m%d', event_date)) AS event_date,
      (
        SELECT COALESCE(value.int_value, value.float_value, value.double_value, NULL)
        FROM UNNEST(event_params)
        WHERE
          KEY = 'value'
          AND event_name = 'ad_impression'
      ) AS ad_funded_revenue,
      (
        SELECT value.string_value
        FROM UNNEST(event_params)
        WHERE
          KEY = 'currency'
          AND event_name = 'ad_impression'
      ) AS ad_revenue_currency,
      (
        CASE
          WHEN event_name = 'in_app_purchase' THEN event_value_in_usd
          ELSE 0
          END) AS iap_revenue_usd,
    FROM `project_name.dataset_name.events_2023*`
    WHERE
      platform = 'IOS'
      AND event_name IN (
        'in_app_purchase',
        'ad_impression')
  ),
  total_revenue_table AS (
    SELECT
      it.user_pseudo_id AS user_pseudo_id,
      rt.event_date,
      #combine ad revenue and IAP revenue, assuming both are in same currency
      sum(ifnull(rt.iap_revenue_usd,0) + ifnull(rt.ad_funded_revenue,0)) AS total_revenue,
    FROM install_table it
    INNER JOIN revenue_table rt
      ON it.user_pseudo_id = rt.user_pseudo_id
    WHERE
      rt.event_timestamp >= it.event_timestamp
      AND rt.event_timestamp
        <= it.event_timestamp + 86400000000 * 2  #added 86400 000 millisecond as 24 hours
    GROUP BY 1, 2
  )
SELECT
  event_date,
  sum(CASE WHEN total_revenue BETWEEN 0 AND 0.1 THEN 1 ELSE 0 END) AS Bucket1,
  sum(CASE WHEN total_revenue BETWEEN 0.1 AND 0.5 THEN 1 ELSE 0 END) AS Bucket2,
  sum(CASE WHEN total_revenue BETWEEN 0.5 AND 2 THEN 1 ELSE 0 END) AS Bucket3,
  sum(CASE WHEN total_revenue BETWEEN 2 AND 2.5 THEN 1 ELSE 0 END) AS Bucket4,
  sum(CASE WHEN total_revenue > 2.5 THEN 1 ELSE 0 END) AS Bucket5
FROM total_revenue_table
GROUP BY 1 ORDER BY 1 DESC

以下のように、日ごとの収益範囲ごとにユーザーを返します。バケットの数値が非常に少ない場合や、分布が不均一な場合は、バケット数を調整してクエリを再実行することをおすすめします。

bf7d73085fe94cb6.png

SKAd Network 4.0 について

SKAd Network 4.0 の計測期間は、最大 2 日間、3 ~ 7 日間、8 ~ 35 日間です。上記のアプローチでは、これらの追加のシナリオでデータを分析するためのウィンドウを簡単に変更できます。LOW、MEDIUM、HIGH の大まかな値も使用できます。繰り返しになりますが、このアプローチを使用する場合は 3 つのバケットと考えることができます。つまり、バケット数を 3 に変更すると、LOW、MEDIUM、HIGH のしきい値を取得できます。

4. アトリビューション プロバイダと連携する

プラットフォームによっては、このガイダンスが異なる場合があります。この最新の情報については、プラットフォームの担当者までお問い合わせください。この例では、現在どのようにこれを AppsFlyer にデプロイするかを見ていきます。

前に実行したクエリで、出力として受け取った最終的な範囲は以下のようになります。

ba46f5d993449948.png

  • 範囲 1 : 0 から 0.1
  • 範囲 2 : 0.1 ~ 0.5
  • 範囲 3 : 0.5 ~ 2
  • 範囲 4 : 2 ~ 2.5

最後の収益範囲は無視してください。これは外れ値であり、アプリ アトリビューション プロバイダの平均計算に歪みが生じるためです。

AppsFlyer には SKAN Conversion Studio が用意されており、管理画面でこのデータを非常に簡単に入力できます。4.0 を直接使用するか、「カスタム」を使用します。「新規顧客のみ」モードを選択し測定しますそして、以前の分析で計算した収益の範囲を追加するだけです。

f8c56abdf9b405f4.png

Google 広告のベスト プラクティスと教訓

Google 広告でキャンペーンを運用していて、SKAd Network のコンバージョン値スキーマで効果を測定している方向けに、最適化案をいくつかご紹介いたします。

  • Google 広告で使用している計測期間が、App Attribution プラットフォームで指定したアクティビティ計測期間と一致していることを確認します。SKAd ネットワーク 3.5 の場合、通常は 1 ~ 3 日ほどかかるため、こちらの手順に沿って Google 広告で適宜調整してください。

4fd625aae9d4a43.png

  • Appsflyer を使用している場合、現在のところ、デフォルトのイベント カウンタは 1 です。つまり、ユーザーごとに複数のイベントを考慮していません。SKAN 測定にイベントベース モデルを使用しており、Google 広告の目標コンバージョン単価キャンペーンと比較している場合は、Appsflyer のこちらのガイダンスに沿ってカスタマイズしてください。

6c7a4d703567700a.png

5. 完了

SKAd Network コンバージョン値スキーマのセットアップが完了しました。キャンペーンが公開されると、Google 広告の SKAd Network レポートでデータをモニタリングして、Google 広告キャンペーンのコンバージョン値を確認できるようになりました。

学習した内容

  • GA4F の豊富な元データを BigQuery で探索する方法
  • ビジネスの収益バケットを計算する分析的アプローチ
  • AppsFlyer を使用してスキーマをデプロイする