跟踪应用内收入
跟踪来自应用内购买 (IAP)、订阅和自定义收入来源的收入,以衡量营销活动的绩效和广告支出回报率 (ROAS)。
收入数据通过三个渠道流动:
- 互动报告: 在 Singular 面板中查看收入指标
- 导出日志: 访问详细的 ETL 数据,进行自定义分析
- 实时回传: 将收入事件发送到外部平台
为什么要跟踪收入事件?
- 丰富的分析功能: 获取详细的交易数据,增强 Singular 报告
- 预防欺诈: 包括交易收据(如来自 Google Play 或 Apple App Store 的收据),以验证购买并打击应用内欺诈行为
- 营销活动优化: 将收入与营销工作挂钩,衡量投资回报率
最佳实践:传递完整的购买对象
我们强烈建议传递从 Android(Google Play 账单)或 iOS(StoreKit)应用内购买(IAP)流程返回的购买对象。 这将确保 Singular 收到全面的交易详细信息,包括
- 产品 ID
- 价格
- 货币
- 交易 ID
- 收据数据(用于验证)
通过传递完整的购买对象,您可以获得更丰富的报告,并利用 Singular 的欺诈检测功能,尤其是针对 Google Play 交易。
应用内购买集成
捕获 IAP 购买对象
使用特定平台的 IAP 库检索包含完整交易详细信息的购买对象。
- iOS 平台: 使用 react-native-iap 或类似工具访问 StoreKit 购买详情
- 安卓: 使用 react-native-iap 或 Google Play Billing 库获取购买对象
应用内购买方法
利用购买详情跟踪应用内购买事件,以验证收入和防止欺诈。
方法签名 :
static inAppPurchase(eventName: string, purchase: SingularIOSPurchase | SingularAndroidPurchase): void
static inAppPurchaseWithArgs(eventName: string, purchase: SingularIOSPurchase | SingularAndroidPurchase, args: Record<string, any>): void
有关方法的完整列表,请参阅 inAppPurchase 方法参考 。
完整的 IAP 实现示例
实现完整的购买监听器,捕获 IAP 事件并将其发送到 Singular,同时发送特定于平台的购买对象。
// TurboModule direct API (React Native 0.76+ New Architecture)
import { Platform } from 'react-native';
import NativeSingular from 'singular-react-native/jsNativeSingular';
import {
SingularIOSPurchase,
SingularAndroidPurchase
} from 'singular-react-native';
import {
initConnection,
getProducts,
setPurchaseListener,
finishTransaction,
IAPResponseCode
} from 'react-native-iap';
// Helper function to convert price to a double
const getPriceAsDouble = (product) => {
if (Platform.OS === 'android' && product.priceAmountMicros) {
// Android: Convert priceAmountMicros to double
return product.priceAmountMicros / 1000000.0;
} else if (Platform.OS === 'ios') {
// iOS: Parse price string (e.g., "$4.99" -> 4.99)
const priceString = product.price.replace(/[^0-9.]/g, '');
return parseFloat(priceString) || 0.0;
}
return 0.0; // Fallback
};
// Set up purchase listener
const handlePurchases = async () => {
try {
// Initialize connection
await initConnection();
// Set purchase listener
setPurchaseListener(async ({ responseCode, results }) => {
if (responseCode === IAPResponseCode.OK) {
for (const purchase of results) {
if (!purchase.acknowledged) {
// Fetch product details
const products = await getProducts({ skus: [purchase.productId] });
const product = products.length > 0 ? products[0] : null;
if (!product) return;
// Create purchase object
let singularPurchase = null;
if (Platform.OS === 'ios') {
singularPurchase = new SingularIOSPurchase(
getPriceAsDouble(product),
product.currency ?? 'USD',
purchase.productId,
purchase.transactionId ?? '',
purchase.transactionReceipt
);
} else if (Platform.OS === 'android') {
const jsonData = JSON.parse(purchase.transactionReceipt || '{}');
const receipt = jsonData.purchaseToken || '';
singularPurchase = new SingularAndroidPurchase(
getPriceAsDouble(product),
product.currency ?? 'USD',
purchase.transactionReceipt,
purchase.signatureAndroid
);
} else {
return;
}
// Track in-app purchase
NativeSingular.inAppPurchase('iap_purchase', singularPurchase);
// Complete the purchase
await finishTransaction(purchase, Platform.OS === 'ios');
}
}
}
});
} catch (error) {
console.error('Error handling purchases:', error);
}
};
// Call handlePurchases when your app starts
handlePurchases();
import { Platform } from 'react-native';
import {
Singular,
SingularIOSPurchase,
SingularAndroidPurchase
} from 'singular-react-native';
import {
initConnection,
getProducts,
setPurchaseListener,
finishTransaction,
IAPResponseCode
} from 'react-native-iap';
// Helper function to convert price to a double
const getPriceAsDouble = (product) => {
if (Platform.OS === 'android' && product.priceAmountMicros) {
// Android: Convert priceAmountMicros to double
return product.priceAmountMicros / 1000000.0;
} else if (Platform.OS === 'ios') {
// iOS: Parse price string (e.g., "$4.99" -> 4.99)
const priceString = product.price.replace(/[^0-9.]/g, '');
return parseFloat(priceString) || 0.0;
}
return 0.0; // Fallback
};
// Set up purchase listener
const handlePurchases = async () => {
try {
// Initialize connection
await initConnection();
// Set purchase listener
setPurchaseListener(async ({ responseCode, results }) => {
if (responseCode === IAPResponseCode.OK) {
for (const purchase of results) {
if (!purchase.acknowledged) {
// Fetch product details
const products = await getProducts({ skus: [purchase.productId] });
const product = products.length > 0 ? products[0] : null;
if (!product) return;
// Create purchase object
let singularPurchase = null;
if (Platform.OS === 'ios') {
singularPurchase = new SingularIOSPurchase(
getPriceAsDouble(product), // Price as double, e.g., 4.99
product.currency ?? 'USD', // Currency code, e.g., "USD"
purchase.productId, // e.g., "com.example.premium_subscription"
purchase.transactionId ?? '', // e.g., "1000000823456789"
purchase.transactionReceipt // JWS receipt from StoreKit
);
} else if (Platform.OS === 'android') {
// Parse transactionReceipt to extract purchaseToken
const jsonData = JSON.parse(purchase.transactionReceipt || '{}');
const receipt = jsonData.purchaseToken || '';
singularPurchase = new SingularAndroidPurchase(
getPriceAsDouble(product), // Price as double, e.g., 4.99
product.currency ?? 'USD', // Currency code, e.g., "USD"
purchase.transactionReceipt, // Full JSON receipt from Google Play
purchase.signatureAndroid // Signature from Google Play
);
} else {
return; // Unsupported platform
}
// Track in-app purchase
Singular.inAppPurchase('iap_purchase', singularPurchase);
// Complete the purchase
await finishTransaction(purchase, Platform.OS === 'ios');
}
}
}
});
} catch (error) {
console.error('Error handling purchases:', error);
}
};
// Call handlePurchases when your app starts
handlePurchases();
手动收入跟踪
无需购买验证的收入
通过传递货币、金额和可选产品详细信息来跟踪收入,而无需购买对象。请注意,此方法不提供用于验证的交易收据。
重要:
在发送没有有效购买对象的收入事件时,Singular 不会验证交易。我们强烈建议尽可能使用上述
inAppPurchase()
方法。
注意:
以三个字母的 ISO 4217 货币代码形式传递货币,如
USD
,
EUR
,
INR
。
收入方法
跟踪具有指定货币和金额的简单收入事件。
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/jsNativeSingular';
// Track revenue without product details
NativeSingular.revenue('USD', 4.99);
import { Singular } from 'singular-react-native';
// Track revenue without product details
Singular.revenue('USD', 4.99);
方法签名 :
static revenue(currency: string, amount: number): void
有关方法的完整列表,请参阅 收入方法参考 。
RevenueWithArgs 方法
跟踪带有指定货币、金额和附加自定义属性的收入事件。
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/jsNativeSingular';
// Track revenue with attributes
NativeSingular.revenueWithArgs('USD', 9.98, {
productSKU: 'coin_package_abc123',
productName: 'Coin Pack 10',
productCategory: 'Bundles',
productQuantity: 2,
productPrice: 4.99,
transaction_id: 'T12345'
});
import { Singular } from 'singular-react-native';
// Track revenue with attributes
Singular.revenueWithArgs('USD', 9.98, {
productSKU: 'coin_package_abc123',
productName: 'Coin Pack 10',
productCategory: 'Bundles',
productQuantity: 2,
productPrice: 4.99,
transaction_id: 'T12345'
});
方法签名 :
static revenueWithArgs(currency: string, amount: number, args: Record<string, any>): void
有关方法的完整列表,请参见 revenueWithArgs 方法参考 。
自定义收入方法
使用指定的事件名称、货币和金额跟踪自定义收入事件。
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/jsNativeSingular';
// Track custom revenue event
NativeSingular.customRevenue('PremiumUpgrade', 'USD', 9.99);
import { Singular } from 'singular-react-native';
// Track custom revenue event
Singular.customRevenue('PremiumUpgrade', 'USD', 9.99);
方法签名 :
static customRevenue(eventName: string, currency: string, amount: number): void
有关方法的完整列表,请参见 customRevenue 方法参考 。
CustomRevenueWithArgs 方法
使用指定的事件名称、货币、金额和其他自定义属性跟踪自定义收入事件。
// TurboModule direct API (React Native 0.76+ New Architecture)
import NativeSingular from 'singular-react-native/jsNativeSingular';
// Track custom revenue event with attributes
NativeSingular.customRevenueWithArgs('PremiumBundlePurchase', 'USD', 99.99, {
productSKU: 'premium_bundle_xyz',
productName: 'Premium Bundle',
productCategory: 'Bundles',
productQuantity: 1,
productPrice: 99.99,
discount_applied: true
});
import { Singular } from 'singular-react-native';
// Track custom revenue event with attributes
Singular.customRevenueWithArgs('PremiumBundlePurchase', 'USD', 99.99, {
productSKU: 'premium_bundle_xyz',
productName: 'Premium Bundle',
productCategory: 'Bundles',
productQuantity: 1,
productPrice: 99.99,
discount_applied: true
});
方法签名 :
static customRevenueWithArgs(eventName: string, currency: string, amount: number, args: Record<string, any>): void
有关方法的完整列表,请参见 customRevenueWithArgs 方法参考 。
订阅收入
跟踪订阅
Singular 提供了使用 Singular SDK 实现订阅事件的综合指南。该指南涵盖跨各种平台的应用内订阅事件跟踪。
- 如果您想跟踪订阅收入,请阅读《 订阅事件技术实施指南
混合事件跟踪(高级)
Singular 建议通过集成到应用程序中的 Singular SDK 发送所有事件和收入,以获得最佳归因。不过,必要时,Singular 也可以从其他来源收集事件。
在Singular SDK之外发送的事件必须符合Singular的 服务器到服务器事件文档要求 ,并提供匹配的设备标识符,以便正确归因。
重要:
如果服务器到服务器事件请求中使用的设备标识符在 Singular 中没有匹配的设备标识符,就会出现差异。请注意以下可能性:
- 早期事件: 如果 在 Singular SDK 从应用程序会话中记录设备标识符 之前 收到事件请求,事件请求将被视为未知设备的 "第一次会话",Singular 将把设备归因为 自然量归因 。
- 不匹配的标识符: 如果Singular SDK记录了设备标识符,但与服务器到服务器事件请求中指定的设备标识符不同,则事件将被 错误归因
混合事件跟踪指南
从内部服务器发送事件
从内部服务器收集收入数据,分析营销活动的绩效和投资回报率。
要求:
- 捕获设备标识符: 从应用内注册或登录事件中捕获并传递设备标识符,并将此数据与服务器上的用户 ID 一起存储。由于用户的设备标识符可能会发生变化,因此应在用户生成应用程序会话时更新标识符。这将确保服务器端事件归因于正确的设备
- 平台特定标识符: 服务器端事件是平台特定的,只能使用与设备平台相匹配的设备标识符发送(例如,iOS 设备使用 IDFA 或 IDFV,Android 设备使用 GAID)
- 实时更新: 使用Singular内部商业智能回传机制将事件实时推送到内部端点,以便在服务器端更新数据集。请参阅 内部 BI 回传常见问题
- 实施细节: 查看 "服务器到服务器集成 "指南中的 " 跟踪收入 "部分了解详情
从收入提供商发送事件
集成 RevenueCat 或 adapty 等第三方收入提供商,向 Singular 发送购买和订阅收入。
支持的供应商:
- RevenueCat: 在 RevenueCat 文档 中了解更多信息
- adapty: 在 adapty 文档 中了解更多信息
- Superwall: 在 Superwall 文档 中了解更多信息
- Xsolla: 在 Xsolla 文档 中了解更多信息
从Segment发送事件
通过在Segment中添加 "云模式 "目标,使Segment能够与Singular SDK并行发送事件到Singular。
详细设置说明请参阅 Singular-Segment Integration 实施指南。