Server-to-Server - 集成指南

Server-to-Server - 集成指南

实现 Singular 的 REST API 以进行完整的服务器端追踪,作为 SDK 集成的替代方案,从而全面控制数据收集、传输和归因工作流。


概述

Server-to-Server 使用场景

Server-to-Server (S2S) 集成提供 REST API 端点,用于构建完整的归因和分析解决方案,这些方案在您的后端基础设施上运行,无需在客户端应用中嵌入 Singular SDK。

集成方式:

  • 纯 S2S: 100% 服务器端实现,同时处理会话追踪和事件追踪
  • 混合模式: 由 Singular SDK 管理会话,同时由服务器端处理事件追踪

混合集成模式

混合集成将用于会话管理的 Singular SDK 与用于后端事件追踪的服务器端 EVENT API 相结合,在实现的简便性与服务器端的灵活性之间取得平衡。

混合模式的优势:

  • SDK 自动处理复杂的会话逻辑、深度链接和设备数据收集
  • 服务器针对在后端系统中处理的交易发送事件
  • 降低客户端实现的复杂度
  • 无需 SESSION 端点——由 SDK 管理会话生命周期

混合 S2S 数据流

设备数据获取方法:

  1. 客户端管理流程: 在客户端捕获所需的数据点,并通过内部 API 转发到服务器,以便配合 Singular EVENT 端点使用
  2. Internal BI 回传: 配置 Singular Internal BI 回传,以便在安装、再互动或事件发生后实时接收包含设备标识符的 JSON 负载( 设置指南

设备图谱维护: 这两种方法都需要服务器端逻辑来维护设备图谱。当 SDK 检测到设备标识符发生变化时,请相应地更新服务器,以确保追踪的准确性。

实现资源:


关键集成原则

原则 说明
灵活性 全面控制数据收集和传输时机
功能对等 在提供适当数据的情况下支持所有 SDK 功能
集成路径 客户端 → 您的服务器 → Singular API
实时处理 一次处理一个请求——不支持批量处理
顺序流程 事件必须按时间先后顺序处理
不去重 Singular 不进行去重——请在服务器端实现去重
数据永久性 设备级数据一经摄取便无法删除——请在发送前进行校验

集成要求

纯 S2S 集成需要为会话追踪和事件追踪实现全面的数据管道。

  1. 数据收集: 从客户端应用收集所需的数据点
  2. 设备图谱: 将数据转发到服务器并维护设备标识符存储
  3. 会话请求: 通过 SESSION API 发送会话通知
  4. 响应处理: 处理 Singular 的响应并将其转发回客户端应用
  5. 事件请求: 通过 EVENT API 转发事件

REST API 端点

Singular 提供两个主要的 REST API 端点,用于 Server-to-Server 的会话追踪和事件追踪。

Session 端点

会话追踪 API

SESSION 端点向 Singular 通知应用打开事件,以初始化用户会话,用于归因和留存追踪。

GET https://s2s.singular.net/api/v1/launch

完整参考: SESSION 端点 API 参考


Event 端点

事件追踪 API

EVENT 端点追踪应用内事件和收入,用于归因分析和广告系列优化。

GET https://s2s.singular.net/api/v1/evt

完整参考: EVENT 端点 API 参考


实现阶段

成功的 S2S 集成需要按顺序执行四个关键实现阶段,以实现最佳的数据质量和归因准确性。

阶段 1:数据收集

必需的数据点

建立稳健的数据收集策略,捕获 Singular 平台功能所需的所有参数。

所有必填参数均为强制要求: 遗漏必填参数会导致数据差异和归因错误。没有任何参数是可选的。

异步函数处理: 在收集客户端数据以传输到服务器时,请等待异步函数完成并处理边缘情况。这是导致数据缺失和部分归因的常见问题。

实现资源:


阶段 2:实时流式传输

关键时机要求

实时数据流式传输可保持归因准确性,并支持对时间敏感的功能,例如 SKAdNetwork 转化值更新。

对归因的影响:

  • 延迟的会话: 会严重影响归因准确性——系统需要精确的时间数据才能进行广告系列关联
  • SKAdNetwork 计时器: 转化值在设备上有严格的计时窗口,因此实时流式传输至关重要。延迟会导致转化值更新缺失和广告系列数据不完整

最佳实践:

  • 针对应用会话启动实现服务器端事件监听器
  • 携带所有必填参数立即转发 会话数据
  • 针对应用内事件实现服务器端事件监听器
  • 携带所有必填参数立即转发 事件数据
  • 使用 webhook 架构实现可靠的数据传输
  • 为失败的请求实现重试机制
  • 监控数据流以进行质量保证

阶段 3:响应处理

双向通信

响应处理将服务器端的 API 交互与客户端功能连接起来,从而实现延迟深度链接和转化值更新。

主要响应类型:

  • 延迟深度链接: API 响应包含待处理的深度链接数据,需要立即转发到应用,以进行用户路由和个性化
  • 转化值: 必须迅速将 iOS SKAdNetwork 转化值转发到应用,以实现准确的广告系列衡量

最佳实践:

  • 在服务器基础设施上实现响应处理
  • 解析并校验 Singular API 响应
  • 将相关响应数据转发到客户端应用(对 iOS SKAdNetwork 至关重要)
  • 实现客户端响应处理
  • 使用适当的 HTTP 状态码优雅地处理错误
  • 记录失败的响应以供重试机制使用

阶段 4:测试与验证

数据流验证

测试阶段在生产部署之前验证完整的数据管道功能和归因准确性。

会话归因流程:

  • 首次会话(新安装): Singular 识别新安装并触发安装归因流程
  • 符合再互动条件: Singular 触发再互动归因流程( 再互动常见问题
  • 标准会话: Singular 记录会话,用于用户活动和留存指标

关键时机要求:

  1. 会话先于事件: 在任何事件之前,必须先收到单个 SESSION。SDK 在应用打开时触发会话,然后发送应用内事件。在后台运行 1 分钟以上后,会话超时。当应用返回前台时发送新会话。请使用应用生命周期事件和计时器进行会话管理
  2. 实时事件: 应用中发生的事件必须在其相应会话之后实时发送

验证清单:

  • 测试会话数据流——验证首次会话和后续会话具有正确的数据点和值
  • 确认仅在会话上报给 Singular 后才收到事件(在会话之前发生的事件会产生自然量归因)
  • 确认会话响应已被处理并传递给客户端应用(对延迟深度链接至关重要)

集成完成:

  • ✓ 数据收集和存储已验证
  • ✓ 向 Singular 的实时流式传输已验证
  • ✓ 响应处理和日志记录已验证
  • ✓ 所有测试数据流已验证

测试指南: S2S 集成测试指南


高级功能

通过高级归因处理、深度链接、跨设备追踪和平台专属功能来增强 S2S 集成。

Apple Search Ads 归因

iOS Search Ads 集成

Apple Search Ads 是一个自归因网络 (SAN),需要通过 Apple 框架进行平台专属的归因实现。

框架支持:

双重实现: 在 iAd 被弃用之前,请同时实现 iAd 和 AdServices 框架。Singular 在归因和报告中优先采用 AdServices 信号而非 iAd 信号。

完整指南: Apple Search Ads 集成文档


iAd 框架实现

针对 iOS 14.2 及更低版本,通过 iAd 框架获取并发送 Apple Search Ads 归因数据。

步骤 1:获取归因数据

Objective-C
#import <iAd/iAd.h>

Class ADClientClass = NSClassFromString(@"ADClient");

if (ADClientClass) {
    id sharedClient = [ADClientClass performSelector:@selector(sharedClient)];

    if ([sharedClient respondsToSelector:@selector(requestAttributionDetailsWithBlock:)]) {
        [sharedClient requestAttributionDetailsWithBlock:^(NSDictionary *attributionDetails, NSError *error) {
            if (attributionDetails && attributionDetails.count  0) {
                // REPORT attributionDetails FROM YOUR APP TO YOUR SERVER
            }
        }];
    }
}

延迟处理: 点击 Search Ads 的用户可能会立即下载并打开应用。请通过以下方式防止归因时机问题:

  1. 在获取归因数据之前设置几秒钟的延迟
  2. 如果响应为 False 或返回错误码(0、2、3),则实现重试逻辑。2 秒后重试

步骤 2:发送到 Singular

通过 EVENT 端点 上报使用保留名称 __iAd_Attribution__ 的事件,并将归因 JSON 作为 e 参数传递。

时机要求:

  • iOS 13+:在安装/重新安装后的首次会话之后,立即发送 __iAd_Attribution__ 事件。否则 Apple Search Ads 数据将不会被用于归因
  • iOS 14+:归因响应仅在 特定条件下 可用,如果 ATT 状态为 ATTrackingManager.AuthorizationStatus.denied 则不可用

AdServices 框架实现

针对 iOS 14.3 及更高版本,通过 AdServices 框架获取并发送归因令牌。

步骤 1:获取归因令牌

Objective-C
#import <AdServices/AdServices.h>

NSError *error = nil;
Class AAAttributionClass = NSClassFromString(@"AAAttribution");
if (AAAttributionClass) {
    NSString *attributionToken = [AAAttributionClass attributionTokenWithError:&error];
    if (!error && attributionToken) {
        // Handle attributionToken
    }
}

令牌特性:

  • 在设备上生成
  • 缓存 5 分钟——若在过期后调用 attributionToken() 则生成新令牌
  • 有效期为 24 小时

步骤 2:发送到 Singular

对令牌进行 URL 编码,并在每次安装和重新安装后的首次会话上,将其作为 attribution_token 参数附加到 SESSION 端点


Google Play Install Referrer

Android 安装归因

Google Play Install Referrer 提供最准确的 Android 安装归因,包含用户在到达 Play 商店之前来源的信息。

以下情况必需:

更多信息: Google Install Referrer 文档

实现步骤:

  1. 在首次打开应用时使用 Play Install Referrer API 获取 install referrer
  2. 通过 SESSION 端点 上报会话,其中包含带有必需属性的 install_ref JSON 参数

install_ref 属性:

属性 说明
referrer 来自 Play Install Referrer API 的 referrer 值(JSON 对象——编码为字符串)
referrer_source 指定为 "service"
clickTimestampSeconds 来自 API 的点击时间戳(例如 "1550420123")
installBeginTimestampSeconds 来自 API 的安装开始时间
current_device_time 当前设备时间(毫秒,例如 "1550420454906")

Meta Install Referrer

Facebook 归因增强

自 2025 年 6 月 18 日起: Meta 的 高级移动衡量 (AMM) 消除了实现 Meta Install Referrer 的需要。如果已启用 AMM,则不推荐使用。

Meta Referrer 是一种 Android 专属的衡量解决方案,提供细粒度的用户级安装归因数据,结合了 Google Play Install Referrer 和 Meta Install Referrer 技术。

了解更多: Meta Referrer 常见问题

实现步骤:

  1. 按照 Meta 的文档 在首次打开应用时获取 Meta install referrer
  2. 通过 SESSION 端点 上报会话,其中包含带有必需属性的 meta_ref JSON 参数

meta_ref 属性:

属性 说明
is_ct 来自 Meta Install Referrer 的 is_ct(0 或 1)
install_referrer 来自 Meta Install Referrer 的 install_referrer
actual_timestamp 来自 Meta Install Referrer 的 actual_timestamp(例如 1693978124)

Singular Links 与深度链接

为 Singular 追踪链接实现深度链接和延迟深度链接,使用户能够从广告系列无缝跳转到您应用中的特定页面。

深度链接是一个可点击的链接,可在应用内打开特定内容。需要支持两种场景:

  • 深度链接(直接):用户已经安装了应用。他们点击 Singular Link,应用会直接打开到正确的内容。
  • 延迟深度链接 (DDL):用户尚未安装应用。他们点击链接,从商店安装,并在首次打开时应用仍会将他们路由到目标内容。

在 SDK 集成中,Singular 会自动处理其中大部分工作。而在 Server-to-Server (S2S) 集成中,设备上没有 SDK,因此您的团队需要负责两项额外的工作:将应用收到的深度链接向上传递给 Singular,以及读取 Singular 返回的延迟深度链接并路由用户。两者都通过 SESSION 端点进行:

GET https://s2s.singular.net/api/v1/launch

资源:深度链接常见问题 | Singular Links 常见问题

三项配置一览

步骤 作用 发生位置
1. 应用层级 使 Singular Links 能够打开您的应用(iOS Universal Links / Android App Links),并定义深度链接目标。 Apple/Google 配置 + Singular 控制台(Apps 与 Manage Links)
2. SESSION(入站) Singular 接收深度链接结果。您的应用通过 openuri 参数将打开的链接向上传递。 SESSION 请求 → Singular
3. SESSION(出站) 应用接收 DDL 结果。Singular 在响应中返回延迟深度链接,您的服务器将其转发给应用。 SESSION 响应 → 您的服务器 → 应用

步骤 1:应用层级配置

在任何深度链接生效之前,Singular Links 必须被操作系统识别为 iOS Universal Links 和 Android App Links,以便点击链接时打开您的应用而非浏览器。作为后备方案,也支持传统的 URI 应用 scheme。

请遵循规范的设置指南了解平台的详细步骤,然后确认下方每一项均已完成。详细步骤位于 Singular Links 前提条件如何配置深度链接。这里的清单为您提供了必需的顺序以及团队最常遗漏的要点。

配置清单:

  1. Attribution > Manage Links > Manage Link Domains添加链接子域名(例如 yourbrand.sng.link)。这是您的 Singular Links 所使用的主机。
  2. iOS — Universal Links:applinks:yourbrand.sng.link 启用 Associated Domains 能力,然后从 Apple Developer Portal 将您的 App Prefix / Team ID 复制到 Settings > Apps > [iOS app] > Show Advanced Settings 中。也可以选择在 Xcode 中将应用 scheme 后备注册为 URL Type。
  3. Android — App Links:生成您的 SHA-256 签名指纹(生产环境使用 Play Console,调试环境使用 keytool),为您的 Singular 域名向 AndroidManifest.xml 添加一个 autoVerify intent filter,然后将指纹粘贴到 Settings > Apps > [Android app] > Show Advanced Settings > App Links SHA256 fingerprints 中。
  4. Attribution > Manage Links > Create Link定义深度链接(参见下方的字段映射)。

重要提示:在 iOS 上,如果跳过了 Team ID 这一步,每个 Singular Link 都会再营销到 App Store,深度链接将无法生效。这是正确构建的链接无法打开应用的最常见原因。

映射 Manage Links 再营销字段

当您创建链接时,三个再营销字段会直接映射到稍后在 API 中使用的三个深度链接概念:

Manage Links 中的字段 含义
如果应用未安装,则跳转到 后备再营销,通常是您的 App Store / Play Store 页面。
如果应用已安装,则跳转到 深度链接,即面向现有用户的应用内目标(步骤 2)。
安装后,直接跳转到 延迟深度链接,即面向新用户安装后的目标(步骤 3)。通常与深度链接的值相同。

开发交接:工程团队应提供每个平台的深度链接 scheme 以及目标 URL 列表(例如 myapp://autumnfashion)。


步骤 2:SESSION(入站)——将深度链接发送到 Singular

当应用从 Singular Link 打开时,捕获完整的打开 URL,并在 SESSION 请求的 openuri 参数中(经 URL 编码)将其发送到 Singular。这就是 Singular 将会话归因到该链接并上报深度链接结果的方式。使用 Singular Links 时为必需项。

在深度链接打开时始终发送 SESSION。每当应用通过深度链接、Universal Link 或 App Link 打开时,发送一个填充了 openuri 的 SESSION 请求,即使该会话通常被视为仍处于活动状态(即不论超时窗口如何)。

URL 上携带的 Singular Link 参数

参数 含义
_dl 深度链接值(iOS 和 Android 使用相同的目标)。
_ios_dl / _android_dl 平台专属的深度链接值,当各平台的值不同时使用。
_p 透传参数,一个经 URL 编码的 JSON 或纯字符串,用于自定义路由。

在应用中捕获打开 URL

应用需要处理程序代码来接收打开 URL,并将其转发到您的服务器,以便包含在 SESSION 请求中。

iOS (Swift):

// Custom scheme / direct opens
func scene(_ scene: UIScene,
           openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else { return }
    SessionReporter.report(openURL: url.absoluteString)
}

// Universal Links arrive via:
func scene(_ scene: UIScene,
           continue userActivity: NSUserActivity) {
    if let url = userActivity.webpageURL {
        SessionReporter.report(openURL: url.absoluteString)
    }
}

Android (Kotlin):

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    intent?.data?.let { uri ->
        SessionReporter.report(uri.toString())
    }
}

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    intent?.data?.let { SessionReporter.report(it.toString()) }
}

发送带有 openuri 的 SESSION 请求

从您的服务器,将捕获的 URL(经 URL 编码)作为 openuri 包含进来:

curl -G https://s2s.singular.net/api/v1/launch \
  --data-urlencode "a=<SDK key>" \
  --data-urlencode "p=Android" \
  --data-urlencode "i=com.yourcompany.app" \
  --data-urlencode "aifa=<GAID>" \
  --data-urlencode "n=YourAppName" \
  --data-urlencode "openuri=myapp://home/page?queryparam1=value1"

短链接解析

如果用户打开的是缩短的 Singular Link,请同时发送 singular_link_resolve_required=true。Singular 会返回展开后的长链接,以便您解析深度链接和透传值。

示例响应:

{
  "status": "ok",
  "resolved_singular_link": "https://myapp.sng.link/A59c0/nha7?_dl=myapp%3A%2F%2Fdeeplink&_ddl=myapp%3A%2F%2Fdeferred-deeplink&_p=passthroughvalue"
}

动态透传参数

如果您的组织为某个链接配置了动态透传,则深度链接 URL 会包含 _p 参数,其值为经 URL 编码的 JSON 字符串或非结构化字符串,用于内容路由。参见 动态透传参数

参考:SESSION 端点 API 参考(深度链接参数)。


步骤 3:SESSION(出站)——将延迟深度链接转发给应用

对于在点击链接后安装应用的用户,Singular 会在安装后的首次会话的 SESSION 响应中返回延迟深度链接。您的服务器必须将该值转发回应用,以便它能路由用户。

在首次会话上请求 DDL

在安装后的首次 SESSION 请求上,添加以下两个参数:

参数 用途
install=true 将此标记为全新安装后的首次会话。
ddl_enabled=true 告知 Singular 应用期望在响应中收到延迟深度链接。

示例 SESSION 请求(install + 启用 DDL):

curl -G https://s2s.singular.net/api/v1/launch \
  --data-urlencode "a=<SDK key>" \
  --data-urlencode "p=Android" \
  --data-urlencode "i=com.yourcompany.app" \
  --data-urlencode "aifa=<GAID>" \
  --data-urlencode "n=YourAppName" \
  --data-urlencode "install=true" \
  --data-urlencode "ddl_enabled=true"

读取响应并将其转发给应用

如果安装来自携带延迟深度链接的追踪链接,Singular 会返回:

响应字段 如何处理
deferred_deeplink 深度链接地址。转发给应用并将用户路由到匹配的内容。
deferred_passthrough 附加到链接的任何透传参数。用于个性化。

示例 SESSION 响应:

{
  "deferred_deeplink": "myapp://deferred-deeplink",
  "status": "ok",
  "deferred_passthrough": "passthroughvalue"
}

响应处理为必需项。在纯 S2S 设置中,Singular 无法直接与设备通信。您的后端必须解析 SESSION 响应,并将 deferred_deeplink(以及 deferred_passthrough)转发回客户端应用,由您的路由代码将用户带到正确的页面。如果未转发该响应,延迟深度链接将会静默失败。


测试与验证

  • 延迟深度链接:在未安装应用的设备上,点击链接并确认您跳转到商店。安装并打开后,应用应显示目标内容。
  • 直接深度链接:在已安装应用的情况下,点击链接并确认应用直接打开到目标内容。
  • SESSION 顺序:确认在任何事件之前都先收到单个 SESSION,并且 SESSION 响应已被解析并传递给客户端(对延迟深度链接至关重要)。
  • openuri 已填充:验证深度链接打开会发送带有 openuri 设置的 SESSION,不论超时窗口如何。

测试指南:测试您的集成 | 测试追踪链接


其他功能

实现跨设备追踪、收入追踪、卸载监控和数据隐私合规,以进行全面的分析。

跨设备追踪

自定义用户 ID 实现

利用 custom_user_id 参数将用户与设备级会话关联起来,以进行跨设备报告和用户级分析。

隐私合规: 遵守数据隐私政策,避免在 custom_user_id 中使用个人身份信息 (PII)。请使用经哈希处理的用户名、电子邮件或随机生成的字符串作为唯一用户标识符。

在维护用户隐私的同时,实现全面的跨设备报告、用户级数据导出和 Internal BI 回传。

更多信息: 自定义用户 ID 参数


收入追踪

应用内购买上报

追踪应用内购买产生的收入,用于 ROI 分析、广告系列效果衡量以及导出/回传的数据丰富。

使用 EVENT 端点 配合 收入参数

  • is_revenue_event :将事件标记为收入事件(如果事件名称为 __iap__ 或金额 > 0,则可跳过)
  • purchase_receipt :Android/iOS 应用内购买对象——强烈建议提供,用于交易详情和报告丰富
  • receipt_signature (Android):强烈建议提供,用于交易校验和欺诈预防
  • amt :收入金额,类型为 Double(例如 "amt=1.99")
  • cur :ISO 4217 货币代码(例如 "cur=USD")

实现指南: 订阅状态管理


卸载追踪

静默推送通知设置

通过在每次会话通知中发送推送令牌,使用设备静默推送通知来追踪卸载。

设置要求:

  1. 遵循平台专属的卸载追踪设置:
  2. 将平台专属的令牌附加到 SESSION 请求:

iOS 安装收据

收据校验

在上报 iOS 会话时,于 install_receipt 参数中传递 iOS 安装收据。

Swift
import Foundation
import StoreKit

class ReceiptManager {
    static func getInstallReceipt() - String? {
        if #available(iOS 18.0, *) {
            let semaphore = DispatchSemaphore(value: 0)
            var result: String?

            Task {
                do {
                    let transaction = try await AppTransaction.shared
                    result = transaction.jwsRepresentation
                    semaphore.signal()
                } catch {
                    debugPrint("Failed to get app transaction: \(error.localizedDescription)")
                    semaphore.signal()
                }
            }

            semaphore.wait()
            return result

        } else {
            guard let receiptURL = Bundle.main.appStoreReceiptURL else {
                debugPrint("Receipt URL not found")
                return nil
            }

            do {
                let receiptData = try Data(contentsOf: receiptURL, options: .uncached)
                return receiptData.base64EncodedString(options: [])
            } catch {
                debugPrint("Failed to read receipt: \(error.localizedDescription)")
                return nil
            }
        }
    }
}

数据隐私合规

用户同意处理

向 Singular 通知最终用户对数据共享的同意情况,以遵守 GDPR、CCPA 和其他隐私法规。

使用 data_sharing_options 参数来传达用户的选择:

  • {"limit_data_sharing":false} :用户已同意(选择加入)共享信息
  • {"limit_data_sharing":true} :用户拒绝共享信息

Singular 在 用户隐私回传 中使用 limit_data_sharing ,并将信息传递给需要合规的合作伙伴。

可选但建议: 该参数为可选项,但部分归因信息仅在用户明确选择加入时才会由合作伙伴共享。

更多信息: 用户隐私与限制数据共享