인앱 구매 추적
인앱 구매(IAP), 구독, 커스텀 구매원의 구매을 추적하여 캠페인 성과와 광고 투자 구매률(ROAS)을 측정할 수 있습니다.
구매 데이터는 세 가지 채널을 통해 전달됩니다:
- 인터랙티브 보고서: Singular 대시보드에서 구매 지표를 볼 수 있습니다.
- 로그 내보내기: 사용자 지정 분석을 위해 상세한 ETL 데이터에 액세스
- 실시간 포스트백: 구매 이벤트를 외부 플랫폼으로 전송
왜 구매 이벤트를 추적해야 하나요?
- 풍부한 분석: 상세한 거래 데이터를 캡처하여 Singular 리포트 강화
- 사기 방지: 거래 영수증(예: 구글 플레이 또는 애플 앱스토어)을 포함시켜 구매를 검증하고 인앱 사기를 방지하세요.
- 캠페인 최적화: 구매을 마케팅 활동과 연결하여 ROI 측정
모범 사례: 전체 구매 개체 전달
안드로이드(구글 플레이 청구) 또는 iOS(스토어키트)의 인앱 구매(IAP) 프로세스에서 반환된 구매 객체를 전달할 것을 강력히 권장합니다. 이렇게 하면 Singular가 다음과 같은 포괄적인 거래 세부 정보를 수신할 수 있습니다:
- 제품 ID
- 가격
- 통화
- 거래 ID
- 영수증 데이터(유효성 검사용)
전체 구매 개체를 전달하면 더욱 풍부한 리포팅이 가능하며, 특히 구글 플레이 거래에 대한 Singular의 사기 탐지 기능을 활용할 수 있습니다.
인앱 구매 연동
IAP 구매 개체 캡처
플랫폼별 IAP 라이브러리를 사용하여 전체 거래 세부 정보가 포함된 구매 객체를 검색하세요.
- iOS: react-native-iap 또는 이와 유사한 라이브러리를 사용하여 스토어키트 구매 세부 정보에 액세스합니다.
- Android: react-native-iap 또는 구글 플레이 결제 라이브러리를 사용하여 구매 객체를 가져옵니다.
인앱 구매 방법
구매 검증 및 사기 방지를 위해 구매 세부 정보로 인앱 구매 이벤트를 추적합니다.
메소드 서명 :
static inAppPurchase(eventName: string, purchase: SingularIOSPurchase | SingularAndroidPurchase): void
static inAppPurchaseWithArgs(eventName: string, purchase: SingularIOSPurchase | SingularAndroidPurchase, args: Record<string, any>): void
전체 메소드 목록은 인앱 구매 메소드 참조를 참조하세요.
전체 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
CustomRevenue 메서드
지정된 이벤트 이름, 통화 및 금액으로 사용자 지정 구매 이벤트를 추적합니다.
// 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를 사용하여 구독 이벤트를 구현하는 방법에 대한 포괄적인 가이드를 제공합니다. 이 가이드는 다양한 플랫폼에서 인앱 구독 이벤트 추적을 다룹니다.
- 구독 구매을 추적하려면 구독 이벤트 기술 구현 가이드를 읽어보세요.
하이브리드 이벤트 추적(고급)
CDP 및 서드파티 연동 비호환성: SDID는 CDP(Segment, mParticle, RudderStack) 또는 서드파티 구독 제공업체(RevenueCat, Adapty)와 호환되지 않습니다. SDID가 활성화된 경우 이러한 플랫폼을 이벤트 전달에 병행하여 사용할 수 없으며, 이는 불완전하거나 손상된 어트리뷰션으로 이어집니다.
Singular는 최적의 어트리뷰션을 위해 앱에 연동된 Singular SDK를 통해 모든 이벤트와 구매을 전송할 것을 권장합니다. 하지만, 필요한 경우 Singular는 다른 소스에서 이벤트를 수집할 수 있습니다.
Singular SDK 외부에서 전송되는 이벤트는 Singular의 서버 간 이벤트 문서 요구사항을 준수해야 하며, 정확한 어트리뷰션을 위해 일치하는 기기 식별자를 제공해야 합니다.
중요:
서버 간 이벤트 요청에 사용된 디바이스 식별자가 Singular에 일치하는 디바이스 식별자가 없는 경우 불일치가 발생할 수 있습니다. 다음과 같은 가능성에 유의하세요:
- 초기 이벤트: 이벤트 요청이 앱 세션에서 디바이스 식별자를 기록하기 전에 수신된 경우, 이벤트 요청은 알 수 없는 디바이스에 대한 "첫 번째 세션"으로 간주되며, Singular는 해당 디바이스를 오가닉 어 트리뷰션으로 어트리뷰션합니다.
- 불일치 식별자: Singular SDK가 디바이스 식별자를 기록했지만 서버 간 이벤트 요청에 지정된 디바이스 식별자와 다른 경우, 해당 이벤트는 잘못 어트리뷰션됩니다 .
하이브리드 이벤트 추적 가이드
내부 서버에서 이벤트 보내기
내부 서버에서 구매 데이터를 수집하여 캠페인 성과와 ROI를 분석하세요.
요구 사항
- 디바이스 식별자를 캡처합니다: 인앱 등록 또는 로그인 이벤트에서 디바이스 식별자를 캡처하여 전달하고 이 데이터를 서버에 사용자 ID와 함께 저장하세요. 디바이스 식별자는 사용자에 따라 변경될 수 있으므로 사용자가 앱 세션을 생성할 때 식별자를 업데이트하세요. 이렇게 하면 서버 측 이벤트가 올바른 디바이스에 어트리뷰션되도록 보장할 수 있습니다.
- 플랫폼별 식별자: 서버 측 이벤트는 플랫폼별로 다르며 디바이스 플랫폼과 일치하는 디바이스 식별자(예: iOS 디바이스의 경우 IDFA 또는 IDFV, 안드로이드 디바이스의 경우 GAID)로만 전송해야 합니다.
- 실시간 업데이트: Singular 내부 BI 포스트백 메커니즘을 사용하여 이벤트를 내부 엔드포인트에 실시간으로 푸시하여 서버 측의 데이터 집합을 업데이트할 수 있습니다. 내부 BI 포스트백 FAQ를 참조하세요.
- 구현 세부 정보: 자세한 내용은 서버 간 연동 가이드의 구매 추적 섹션을 검토하세요.
구매 제공업체에서 이벤트 보내기
RevenueCat 또는 어댑터와 같은 타사 구매 제공업체를 연동하여 구매 및 구독 구매을 Singular로 전송하세요.
지원되는 제공업체
- RevenueCat: RevenueCat 문서에서 자세히 알아보기
- adapty: 어댑티브: 어댑티브 문서에서 자세히 알아보기
- Superwall: 어댑티브: 어댑티브 문서에서 자세히 알아보기
- Xsolla: 어댑티브: 어댑티브 문서에서 자세히 알아보기
세그먼트에서 이벤트 보내기
세그먼트에 "클라우드 모드" 대상을 추가하여 세그먼트에서 이벤트를 Singular SDK와 병행하여 Singular로 전송할 수 있도록 설정하세요.
자세한 설정 지침은 구현 가이드 Singular-Segment 연동을 참조하세요.