1. 简介
开始之前的一些背景信息
如果您是 iOS 应用开发者,那么您一定听说过 iOS 14.5 及更高版本的隐私权更新。为了衡量安装后有意义的转化操作,Apple 提供了 SKAd Network API,让您可以在尊重用户隐私的前提下衡量广告系列的效果。您可以根据自己的业务需求,找出利用 SKAdNetwork 捕获有关广告系列的有用数据分析的最佳方式。在此 Codelab 中,我们将探讨一种示例方法,以利用 BigQuery 中的 GA4F 数据将应用安装后的收入分组到不同的分桶中,然后您可以使用这些分桶与应用归因合作伙伴进行设置。虽然此 Codelab 使用的是基于收入的方法,但您也可以使用基于事件或漏斗的方法进行 SKAN 衡量。如需更详细的指导,请参阅这篇帮助中心文章。这只是一个示例,并非 Google 的官方建议。您可以根据自己的具体业务需求设计自己的架构
我们打算介绍的内容
- 在 BigQuery 中探索 GA4F 数据
- 查找在 0-2 天内完成转化的用户的收入数据
- 将收入数据分组到不同的桶中
- 了解每个分桶中的用户分布情况
- 在 AppsFlyer SKAN Conversion Studio 中实现分桶
前提条件
2. 访问 BigQuery Export
前往 Google Cloud 数据集
前往 GA4F 中的数据集,方法是依次访问项目设置 > 集成 > BigQuery。您需要先启用此切换开关,启用后,数据集大约需要 48 小时才能可供使用。您可以点击下方显示的链接,系统会将您转到 BigQuery

运行一些查询
现在,您已进入 BigQuery,应该会看到生成的每日表。在下面的示例屏幕截图中,我们看到 64 个每日表,因此导出已运行 64 天。如果您是首次访问,可能只会看到 1 个每日表,其中包含前一天的数据。右侧会显示表架构。您可以点击此处查看有关这些字段的更多详细信息
如需开始编写查询,您可以点击查询 > 在新标签页中

然后,您可以在新标签页中尝试运行示例查询

3. 分析收入数据
提取安装数据
现在,为了开始构建收入分桶,我们必须先查看过去 24 到 72 小时内安装应用的用户的数据。SKAdNetwork 4.0 可让您查看 0-2 天内的数据,而 SKAdNetwork 3.5 默认允许查看 24 小时内的数据。(根据应用归因合作伙伴的功能,您或许可以修改此活动回溯期,但一般不得超过 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'
关于此查询,有几点需要注意
- 请将表名称替换为您的 Google Analytics 导出表。您可以使用通配符 查询多个每日表。例如,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 中提取值
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
- 如果您发送的是多种币种,则需要先将这些币种统一为一种币种,才能进行此分析。在此示例中,我们假设广告收入的币种也是美元
输出将如下所示(此处已隐去 user_pseudo_id 列)。

合并这些数据
到目前为止,我们已运行过两个查询,一个用于查找安装并打开应用的用户的数据,另一个用于查找这些用户的收入。现在,我们来回顾一下之前讨论过的 SKAdNetwork 限制。归因回溯期只能在安装后 0-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 和总收入

现在,我们需要将这些数据合并到可用于转化价值范围的桶中。为此,我们将使用 BigQuery 中的 approx_quantiles 函数,该函数会自动为您创建这些范围。在此示例中,假设我们要创建 5 个范围,因此只需使用 SELECT approx_quantiles(total_revenue, 5) AS buckets
接下来,我们将此内容纳入我们的整体查询中
#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 会尝试保持一致的百分位数分布

使用这些分桶分析用户分布
这是一个可选步骤,如果您想了解每个分桶中用户的分布情况,可以执行此步骤。对于我们的示例,上一个查询中返回的分桶范围为
- 0.1
- 0.5
- 2
- 2.5
- 5 [范围配置中不得使用最后一个值]
对于最终范围,我们将忽略最后一个分桶 5,因为这通常是最大值,我们可以直接将 2.5 视为最后一个范围。这是因为应用归因提供商往往会使用范围的平均值来计算 ROAS,因此必须排除异常值,才能进行更统一的计算。
现在,我们尝试查看所有范围中每个日期的用户数量,以便了解每个分桶中的每日用户量。我们可以使用以下示例查询来实现此目的,您可以将分桶值替换为实际数据,查询将如下所示
#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
它应返回每天每个收入范围内的用户,如下所示。如果您发现任何分桶中的数量非常低或总体分布不均匀,不妨调整分桶数量,然后重新运行查询。

简要介绍 SKAdNetwork 4.0
SKAdNetwork 4.0 提供多个转化时间范围,分别为最多 2 天、3-7 天和 8-35 天。在上述方法中,您还可以轻松更改窗口,以分析这些其他场景的数据。此外,还提供 LOW、MEDIUM 和 HIGH 这三个粗略值。同样,如果您想使用这种方法,可以将此视为 3 个分桶。因此,通过将分桶数更改为 3,您可以获得低、中、高三个区间的阈值
4. 与归因提供商一起部署
此指南可能会因具体平台而异。如需了解这方面的最新信息,请与平台代表联系。在此示例中,我们将了解目前如何在 AppsFlyer 上部署此功能
在我们之前运行的查询中,收到的最终范围输出如下所示

- 范围 1:0 到 0.1
- 范围 2:0.1 至 0.5
- 范围 3:0.5 至 2
- 范围 4:2 至 2.5
请注意,我们已决定忽略最后一个收入范围,因为该范围会成为异常值,并使应用归因提供商的平均计算结果出现偏差。
AppsFlyer 提供 SKAN Conversion Studio,您可以在其中直接在界面中输入此值。您可以直接使用 4.0,也可以使用“自定义”模式(如果您使用的是 3.5),然后添加“收入”衡量指标。然后,只需添加您根据之前的分析计算出的收入范围即可。

Google Ads 最佳实践和经验
如果您在 Google Ads 上投放广告系列,并通过 SKAdNetwork 转化价值架构衡量效果,我们想为您提供一些建议
- 确保您在 Google Ads 中使用的转化时间范围与您在应用归因平台上指定的活动时间范围一致。对于 SKAdNetwork 3.5,此时间可能为 1-3 天,因此您可以按照此处列出的步骤在 Google Ads 中相应地调整此时间

- 如果您使用的是 Appsflyer,目前默认的事件计数器为 1,这意味着它不会考虑每位用户的多个事件。如果您使用基于事件的模型进行 SKAN 衡量,并与 Google Ads 中的“目标每次转化费用”广告系列进行比较,可以选择按照 AppsFlyer 的这份指南进行自定义

5. 恭喜
恭喜!您已成功设置 SKAdNetwork 转化价值架构。现在,您可以监控 Google Ads SKAdNetwork 报告中的数据,以便在启用此功能后查看 Google Ads 广告系列的转化价值
您学到的内容
- 如何在 BigQuery 中探索 GA4F 提供的丰富原始数据
- 计算业务收入区间的分析方法
- 使用 AppsFlyer 部署架构