Adjust는 모바일, 콘솔, 커넥티드 TV(CTV) 앱을 위한 서버 간(S2S) 인터페이스를 제공합니다. S2S를 통해 Adjust를 도입하고자 하는 경우, Adjust SDK의 기능을 복제할 수 있도록 앱을 수정해야 합니다. 본 가이드는 다음에 대한 단계별 설명을 제공합니다.
앱에 필요한 업데이트를 수행하는 방법.
Adjust에 S2S 요청을 전송하는 방법.
시작에 앞서
시작 전 수행해야 할 사항은 다음과 같습니다.
S2S 세션 측정 활성화
모바일 앱에 서버 간 인터페이스를 사용하는 경우, Adjust는 해당 앱에 대해 서버 간 세션 측정을 활성화해야 합니다. 자세한 내용은 Adjust 담당자나 support@adjust.com 으로 문의하시기 바랍니다.
서버 간 세션 측정은 특정 플랫폼을 선택할 때 CTV 측정 과 PC 및 콘솔 측정 에 대해 자동으로 활성화됩니다.
S2S 보안 설정
서버 간 활동을 보호하고 스푸핑된 요청을 방지하기위해 S2S 보안을 도입 하시기 바랍니다. Adjust 대시보드에서 토큰을 생성하고 수신되는 각 요청에 포함합니다.
로컬에서 이벤트를 대기하고 유지
사용자는 기기가 오프라인 상태일 때 앱 설치나 세션과 같은 중요한 이벤트를 트리거할 수 있습니다. 정확한 어트리뷰션을 위해 Adjust 서버로 전송될 수 있을 때까지 이러한 이벤트를 포착하고 로컬에 저장해야 합니다.
지속적인 로컬 이벤트 대기열을 구현하려면 다음을 수행합니다.
활동 발생 시 이를 저장할 대기열을 생성합니다.
각 활동에 대해 기기에서 이벤트가 발생한 시점을 나타내는 초 단위의 created_at_unix
타임스탬프(예: 1484085154
)를 포함합니다.
이 대기열을 로컬 스토리지(예: SQLite 데이터베이스 또는 파일)에 저장하면 앱이 다시 시작될 때에도 유지됩니다.
대기열이 비어 있지 않고 기기가 온라인 상태일 때 Adjust 서버로 활동을 전송하도록 시도합니다.
전송이 성공한 후에만 대기열에서 활동을 삭제합니다.
이 접근법은 다음과 같은 시나리오에서 데이터 손실을 완화하는 데 도움이 됩니다.
짧은 네트워크 중단(예: 5G에서 WiFi로의 전환).
연결 없이 연장된 기간.
전송 전에 앱이 충돌하거나 강제 종료.
로컬 대기가 없다면 설치 데이터의 10~20%를 잃을 위험이 있으며, 이는 어트리뷰션 정확도에 큰 영향을 줄 수 있습니다. 이 대기열 시스템을 도입하면 Adjust에 완전하고 정확한 사용자 활동 관련 정보를 전송하여 오프라인에서 발생하는 이벤트에 대해서도 정확한 어트리뷰션을 수행할 수 있습니다.
iOS 프레임워크 추가
특정 iOS 기능을 지원하려면 프레임워크를 프로젝트에 연결해야 합니다. 프로젝트에 프레임워크를 추가하는 방법은 다음과 같습니다.
Xcode에서 프로젝트를 실행합니다.
Project Navigator에서 대상을 선택합니다.
General(일반) 탭으로 이동합니다.
Frameworks, Libraries(프레임워크, 라이브러리) 및 Embedded Content(삽입 콘텐츠) 섹션으로 스크롤합니다.
+ 버튼을 선택합니다.
아래 목록에서 앱에 필요한 프레임워크를 검색하여 추가합니다.
프레임워크 설명 AdSupport.framework
IDFA 수집에 필요합니다. ATT 이전 iOS 버전에 대한 광고 추적 제한 상태를 수집할 때도 필요합니다. AppTrackingTransparency.framework
iOS 14.5 이상을 사용하는 기기에서 AppTrackingTransparency 프롬프트를 제시하고 IDFA를 수집하기 위해 필요합니다. AdServices.framework
Adjust가 Apple 검색 광고 캠페인에 어트리뷰션하기 위해 필요합니다. StoreKit.framework
SKAdNetwork 캠페인 실행을 위해 필요합니다.
필수 파라미터
다음은 각 서버 간 요청에서 요구되는 파라미터입니다.
파라미터 설명 s2s
해당 요청이 서버 간 요청임을 나타냅니다. 반드시 1
로 하드코드되어야 합니다. app_token
Adjust 앱 토큰입니다. os_name
모바일 OS의 이름입니다. 아래에서 옵션 목록을 확인하시기 바랍니다.
android
android-tv
apple-tv
bada
blackberry
fire-tv
ios
linux
macos
nintendo
playstation
roku-os
server
smart-cast
steamos
symbian
tizen
unknown
webos
windows
windows-phone
xbox
서버에서 이러한 파라미터를 생성합니다. 기기와 관계없이 Adjust에 보내는 모든 서버 간 요청에 사용됩니다. 기기별 파라미터는 필요에 따라 추가됩니다. 단순화를 위해 이 가이드에서는 모든 파라미터 처리를 클라이언트 측에서 설명하고 있지만, 실제로는 대부분 서버 측에서 처리됩니다.
// Create dictionary for params to include on all S2S requests to Adjust
var params: [ String : String ] = [ : ]
// The name of the operating system running on the device
params[ "os_name" ] = "ios"
// Replace with your Adjust app token
params[ "app_token" ] = "4w565xzmb54d"
// Create dictionary for params to include on all S2S requests to Adjust
NSMutableDictionary * params = [ NSMutableDictionary dictionary ];
// The name of the operating system running on the device
params [ @"os_name" ] = @"ios" ;
// Replace with your Adjust app token
params [ @"app_token" ] = @"4w565xzmb54d" ;
// Create map for params to include on all S2S requests to Adjust
val params = mutableMapOf < String , String >()
// The name of the operating system running on the device
params[ "os_name" ] = "android"
// Replace with your Adjust app token
params[ "app_token" ] = "4w565xzmb54d"
// Create map for params to include on all S2S requests to Adjust
Map< String , String > params = new HashMap<>();
// The name of the operating system running on the device
params. put ( "os_name" , "android" );
// Replace with your Adjust app token
params. put ( "app_token" , "4w565xzmb54d" );
기기 ID 및 트래킹 상태
모든 서버 간 요청에는 최소 1개 의 기기 식별자가 포함되어야 합니다. 모바일 운영 체제에 의해 도입된 개인정보 보호 조치로 인해 광고 ID를 사용할 수 없는 경우가 있습니다. 따라서 가능한 경우 광고 ID를 포함하고 항상 백업 식별자를 포함해야 합니다.
PC 및 콘솔 / CTV 기기 ID
PC 및 콘솔, CTV 측정의 경우, 기기 식별자로 사용하기 위해 각 콜에 고유한 external_device_id
파라미터를 전달할 수 있습니다. 이 값은 기기를 식별하는 모든 고유한 문자열이 될 수 있습니다.
iOS 기기 ID
IDFA 및 트래킹 상태
IDFA(광고주용 ID)는 사용자가 공유에 동의한 iOS 기기에서만 이용 가능합니다. 일부 앱은 IDFA를 수집하지만 그렇지 않은 앱도 있습니다. 앱의 IDFA 수집 여부와 관계없이 Adjust는 각 요청에서 트래킹 상태 정보를 요구합니다. 아래에서 구현에 상응하는 코드를 사용하시기 바랍니다.
IDFA를 수집하는 앱
Xcode에 ATT 설명을 추가합니다.
프로젝트의 Info.plist
파일을 엽니다.
편집기에서 Information properties List 를 마우스 오른쪽 버튼으로 클릭하고 Add Row 를 선택하여 루트에 키를 추가합니다.
키를 NSUserTrackingUsageDescription
으로 설정합니다.
값을 트래킹 권한 요청 이유를 설명하는 문자열로 설정합니다(예: “이 식별자는 맞춤형 광고를 전달하기 위해 사용됩니다.”). 이 텍스트에 대한 Apple의 가이드라인 을 반드시 검토하시기 바랍니다.
ATT 프롬프트와 IDFA 조회를 구현합니다.
ATT의 요건은 다음과 같습니다.
ATT 지원은 iOS 14부터 시작되지만, IDFA 조회에 대한 사용자 동의는 iOS 14.5 이상 버전에서만 필요합니다. 따라서 Adjust는 ATT 프롬프트를 iOS 14.5 이상 버전의 사용자에게만 타겟팅할 것을 권장합니다.
ATT 프롬프트를 표시하려면 앱이 활성 상태여야 합니다. 앱이 다시 활성 상태가 될 때까지 기다리지 않으면 다른 시스템 프롬프트 이후에 즉시 앱을 표시하지 못할 수 있습니다.
프롬프트를 표시하기에 가장 빠른 위치는 applicationDidBecomeActive
(앱 델리게이트) 또는 sceneDidBecomeActive
(Scene 델리게이트)입니다. didFinishLaunchingWithOptions
(앱 델리게이트)에서는 ATT 프롬프트를 표시할 수 없습니다.
아래의 코드 예시는 이 요구 사항을 모두 충족합니다.
어트리뷰션의 정확도를 높이려면 최초의 세션 요청에 IDFA를 포함하고, 가능한 경우 이후 모든 요청에 포함하시기 바랍니다.
import AppTrackingTransparency
let attStatus: ATTrackingManager.AuthorizationStatus ?
let trackingEnabled: Bool ?
func getIDFAInfo ( completion : @escaping (IDFAInfo) -> Void ) {
// For iOS 14.5+, show ATT prompt to attempt to retrieve IDFA and retrieve ATT
if #available ( iOS 14.5 , * ) {
// Wait briefly to ensure app is active
DispatchQueue.main. asyncAfter ( deadline : . now () + 1.0 ) {
ATTrackingManager. requestTrackingAuthorization { status in
let idfa = (status == .authorized) ?
ASIdentifierManager. shared ().advertisingIdentifier : nil
completion ( IDFAInfo ( idfa : idfa, attStatus : status,
// For earlier versions, don't show ATT prompt. Just get IDFA and tracking
let manager = ASIdentifierManager. shared ()
let idfa = manager.isAdvertisingTrackingEnabled ?
manager.advertisingIdentifier : nil
let trackingEnabled = manager.isAdvertisingTrackingEnabled
completion ( IDFAInfo ( idfa : idfa, attStatus : nil ,
trackingEnabled : trackingEnabled))
// Include IDFA if available
if let idfa = info.idfa ? .uuidString {
// Include ATT status if available,
// otherwise include tracking enabled status, never both
if let attStatus = info.attStatus {
params[ "att_status" ] = String (attStatus. rawValue )
} else if let trackingEnabled = info.trackingEnabled {
params[ "tracking_enabled" ] = trackingEnabled ? "1" : "0"
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <AdSupport/AdSupport.h>
@interface IDFAInfo : NSObject
@property ( nonatomic , strong ) NSUUID * idfa;
@property ( nonatomic , assign ) ATTrackingManagerAuthorizationStatus attStatus;
@property ( nonatomic , strong ) NSNumber * trackingEnabled;
void getIDFAInfo ( void ( ^ completion)(IDFAInfo * )) {
// For iOS 14.5+, show ATT prompt to attempt to retrieve IDFA and retrieve ATT
if (@ available (iOS 14.5 , * )) {
// Wait briefly to ensure app is active
dispatch_after ( dispatch_time (DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
dispatch_get_main_queue (), ^ {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:
^ (ATTrackingManagerAuthorizationStatus status) {
IDFAInfo * info = [[IDFAInfo alloc ] init ];
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
info.idfa = [[ASIdentifierManager sharedManager ]
// For earlier versions, don't show ATT prompt. Just get IDFA and tracking
ASIdentifierManager * manager = [ASIdentifierManager sharedManager ];
IDFAInfo * info = [[IDFAInfo alloc ] init ];
if (manager.isAdvertisingTrackingEnabled) {
info.idfa = manager.advertisingIdentifier;
info.trackingEnabled = @(manager.isAdvertisingTrackingEnabled);
getIDFAInfo ( ^ (IDFAInfo * info) {
// Include IDFA if available
params [ @"idfa" ] = [info.idfa UUIDString ];
// Include ATT status if available, otherwise tracking enabled status, never both
if (info.attStatus != nil ) {
params [ @"att_status" ] = [ NSString stringWithFormat: @" %ld " ,
} else if (info.trackingEnabled != nil ) {
params [ @"tracking_enabled" ] = [info.trackingEnabled boolValue ] ?
IDFA를 수집하지 않는 앱
아래의 코드를 사용하여 트래킹 상태를 확인합니다.
let attStatus: ATTrackingManager.AuthorizationStatus ?
let trackingEnabled: Bool ?
func getTrackingInfo ( completion : @escaping (TrackingInfo) -> Void ) {
// For iOS 14.5+, get ATT status without showing prompt
if #available ( iOS 14.5 , * ) {
let status = ATTrackingManager.trackingAuthorizationStatus
completion ( TrackingInfo ( attStatus : status, trackingEnabled : nil ))
// For earlier versions, get tracking enabled status
let trackingEnabled = ASIdentifierManager. shared ().isAdvertisingTrackingEnabled
completion ( TrackingInfo ( attStatus : nil , trackingEnabled : trackingEnabled))
getTrackingInfo { info in
// Include ATT status if available, otherwise tracking enabled status, never both
if let attStatus = info.attStatus {
params[ "att_status" ] = String (attStatus. rawValue )
} else if let trackingEnabled = info.trackingEnabled {
params[ "tracking_enabled" ] = trackingEnabled ? "1" : "0"
#import <AdSupport/AdSupport.h>
@interface TrackingInfo : NSObject
@property ( nonatomic , assign ) ATTrackingManagerAuthorizationStatus attStatus;
@property ( nonatomic , strong ) NSNumber * trackingEnabled;
@implementation TrackingInfo
void getTrackingInfo ( void ( ^ completion)(TrackingInfo * )) {
// For iOS 14.5+, get ATT status without showing prompt
if (@ available (iOS 14.5 , * )) {
TrackingInfo * info = [[TrackingInfo alloc ] init ];
info.attStatus = ATTrackingManager.trackingAuthorizationStatus;
// For earlier versions, get tracking enabled status
TrackingInfo * info = [[TrackingInfo alloc ] init ];
BOOL enabled = [ASIdentifierManager sharedManager ].isAdvertisingTrackingEnabled;
info.trackingEnabled = @(enabled);
getTrackingInfo ( ^ (TrackingInfo * info) {
// Include ATT status if available, otherwise tracking enabled status, never both
if (info.attStatus != nil ) {
params [ @"att_status" ] = [ NSString stringWithFormat: @" %ld " ,
} else if (info.trackingEnabled != nil ) {
params [ @"tracking_enabled" ] = [info.trackingEnabled boolValue ] ?
IDFV
IDFV(벤더용 ID)는 모든 최신 iOS 기기에서 이용 가능한 백업 식별자입니다.
let idfv: UUID ? = UIDevice.current.identifierForVendor
if let idfvString = idfv ? .uuidString {
params[ "idfv" ] = idfvString
NSUUID * idfv = [[UIDevice currentDevice ] identifierForVendor ];
params [ @"idfv" ] = [idfv UUIDString ];
기본 중복 제거 토큰
앱 삭제 및 재설치 등 앱의 모든 활동을 일관적으로 측정하기 위해 무작위 버전 4 UUID(“기본 중복 제거 토큰”)를 생성하고 iOS 키체인에 저장합니다. 기본 중복 제거 토큰은 모든 기기에 대해 생성해야 하는 백업 식별자입니다.
let bundleId = "com.example.app"
// Collect the primary dedupe token from the keychain
func getPrimaryDedupeToken ( bundleId : String ) -> UUID ? {
// Define the query to search for the token in the keychain
let query: [ String : Any ] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : "primary_dedupe_token" ,
kSecAttrService as String : bundleId,
kSecReturnData as String : true
// Attempt to fetch the token from the keychain
let status = SecItemCopyMatching (query as CFDictionary, & item)
// If the fetch was successful, convert the result to a UUID
guard status == errSecSuccess,
let existingItem = item as? Data,
let uuidString = String ( data : existingItem, encoding : . utf8 ),
let token = UUID ( uuidString : uuidString) else {
// Return nil if the token doesn't exist or couldn't be collected
// Save the primary dedupe token to the keychain
func setPrimaryDedupeToken ( _ token: UUID, bundleId : String ) -> Bool {
let tokenData = token.uuidString. data ( using : . utf8 ) !
// Define the attributes for storing the token in the keychain
let query: [ String : Any ] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : "primary_dedupe_token" ,
kSecAttrService as String : bundleId,
kSecValueData as String : tokenData,
kSecAttrAccessible as String : kSecAttrAccessibleAfterFirstUnlock
// Attempt to add the token to the keychain
let status = SecItemAdd (query as CFDictionary, nil )
// Return true if the token was successfully added, false otherwise
return status == errSecSuccess
// Collect the existing primary dedupe token or create a new one if it doesn't exist
func getOrCreatePrimaryDedupeToken () -> UUID {
// Try to collect an existing token
if let existingToken = getPrimaryDedupeToken ( bundleId : bundleId) {
// If no token exists, generate a new one
// Attempt to save the new token
if setPrimaryDedupeToken (newToken, bundleId : bundleId) {
// If saving fails, throw a fatal error
fatalError ( "Failed to save primary dedupe token" )
let primaryDedupeToken = getOrCreatePrimaryDedupeToken ()
// Convert to lowercase string
params[ "primary_dedupe_token" ] = primaryDedupeToken.uuidString. lowercased ()
#import <Foundation/Foundation.h>
#import <Security/Security.h>
NSString *const bundleId = @"com.example.app" ;
// Collect the primary dedupe token from the keychain
NSUUID * getPrimaryDedupeToken ( NSString * bundleId ) {
// Define the query to search for the token in the keychain
(__bridge id ) kSecClass : (__bridge id ) kSecClassGenericPassword ,
(__bridge id ) kSecAttrAccount : @"primary_dedupe_token" ,
(__bridge id ) kSecAttrService : bundleId,
(__bridge id ) kSecReturnData : @ YES
// Attempt to fetch the token from the keychain
OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)query,
// If the fetch was successful, convert the result to a UUID
if (status == errSecSuccess && item != NULL ) {
NSData * existingItem = (__bridge_transfer NSData * )item;
NSString * uuidString = [[ NSString alloc ]
initWithData:existingItem encoding:NSUTF8StringEncoding ];
return [[NSUUID alloc ] initWithUUIDString: uuidString];
// Return nil if the token doesn't exist or couldn't be collected
// Save the primary dedupe token to the keychain
BOOL setPrimaryDedupeToken (NSUUID * token , NSString * bundleId ) {
NSData * tokenData = [[token UUIDString ]
dataUsingEncoding: NSUTF8StringEncoding ];
// Define the attributes for storing the token in the keychain
(__bridge id ) kSecClass : (__bridge id ) kSecClassGenericPassword ,
(__bridge id ) kSecAttrAccount : @"primary_dedupe_token" ,
(__bridge id ) kSecAttrService : bundleId,
(__bridge id ) kSecValueData : tokenData,
(__bridge id ) kSecAttrAccessible :
(__bridge id ) kSecAttrAccessibleAfterFirstUnlock
// Attempt to add the token to the keychain
OSStatus status = SecItemAdd ((__bridge CFDictionaryRef)query, NULL );
// Return YES if the token was successfully added, NO otherwise
return status == errSecSuccess;
// Collect the existing primary dedupe token or create a new one if it doesn't exist
NSUUID * getOrCreatePrimaryDedupeToken ( void ) {
// Try to collect an existing token
NSUUID * existingToken = getPrimaryDedupeToken (bundleId);
// If no token exists, generate a new one
NSUUID * newToken = [NSUUID UUID ];
// Attempt to save the new token
if ( setPrimaryDedupeToken (newToken, bundleId)) {
// If saving fails, throw an exception
@throw [ NSException exceptionWithName: @"TokenSaveError"
reason: @"Failed to save primary dedupe token"
NSUUID * primaryDedupeToken = getOrCreatePrimaryDedupeToken ();
// Convert to lowercase string
params [ @"primary_dedupe_token" ] = [[primaryDedupeToken UUIDString ]
Google Play 기기 ID(Android)
Google 광고 식별자
GPS ADID(Google 플레이 서비스의 광고 ID)는 사용자가 광고 ID 삭제를 선택하지 않은 경우 Google 플레이 서비스를 통해 Android 기기에서 액세스할 수 있습니다.
play-services-ads-identifier
디펜던시를 앱의 build.gradle
파일에 추가합니다.
implementation ( "com.google.android.gms:play-services-ads-identifier:18.1.0" )
implementation 'com.google.android.gms:play-services-ads-identifier:18.1.0'
AndroidManifest.xml
파일에 다음 권한을 추가합니다.
< uses-permission android:name = "com.google.android.gms.permission.AD_ID" />
앱이 R8 또는 ProGuard를 사용하는 경우 다음 규칙을 proguard-rules.pro
파일에 추가하여 코드 최적화 중 Google 광고 식별자 조회에 필요한 클래스와 메서드를 유지합니다(없는 경우 앱 모듈 디렉토리에 파일 생성).
-keep class com .google.android.gms.common.ConnectionResult {
-keep class com .google.android.gms.ads.identifier.AdvertisingIdClient {
com.google.android.gms.ads.identifier.
AdvertisingIdClient$Info getAdvertisingIdInfo (
android . content . Context );
-keep class com .google.android.gms.ads.identifier.AdvertisingIdClient$Info {
java.lang.String getId ();
boolean isLimitAdTrackingEnabled ();
Google 광고 식별자와 트래킹 상태를 수집하는 코드를 구현합니다.
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun getGoogleAdvertisingIdInfo (
context: Context ): AdvertisingIdClient .Info? {
return withContext (Dispatchers.IO) {
AdvertisingIdClient. getAdvertisingIdInfo (context)
// (for example: Google Play Services not available)
// As getGoogleAdvertisingIdInfo is a suspending function,
// it should be called from within a coroutine scope.
val adInfo = getGoogleAdvertisingIdInfo (context)
// Include Google Advertising ID if tracking is not limited
if ( ! info.isLimitAdTrackingEnabled) {
params[ "gps_adid" ] = info.id
params[ "tracking_enabled" ] = if (info.isLimitAdTrackingEnabled)
App Set ID
App Set ID는 Google 플레이 서비스가 설치되고 API Level 30(Android 11) 이상을 실행하는 모든 Android 기기에서 사용할 수 있는 백업 식별자입니다.
앱의 build.gradle
파일에 필요한 디펜던시를 추가합니다.
implementation ( "com.google.android.gms:play-services-appset:16.1.0" )
implementation 'com.google.android.gms:play-services-appset:16.1.0'
App Set ID를 수집하는 코드를 구현합니다.
import com.google.android.gms.appset.AppSet
import com.google.android.gms.appset.AppSetIdClient
import com.google.android.gms.appset.AppSetIdInfo
import com.google.android.gms.tasks.Tasks
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun getAppSetId (context: Context ): String ? {
return withContext (Dispatchers.IO) {
val client: AppSetIdClient = AppSet. getClient (context)
val taskResult = Tasks. await (client.appSetIdInfo)
// Handle exceptions (for example: Google Play Services not available)
// As getAppSetId is a suspending function,
// it should be called from within a coroutine scope.
val appSetId = getAppSetId (context)
val params = mutableMapOf < String , String >()
params[ "google_app_set_id" ] = id
추가 파라미터
다음 파라미터는 필수가 아닙니다. 이러한 파라미터를 사용하는 경우 모든 요청에 포함해야 합니다.
Unix 타임스탬프
각 서버 간 요청에 Unix 타임스탬프를 추가하면 기기에서 활동이 발생한 시간을 제공하여 어트리뷰션의 정확도가 개선됩니다.
// Unix timestamp of when activity occurred on device
// Code example shows how to retrieve current time in seconds
// Example value: "1484085154"
params[ "created_at_unix" ] = String ( Int ( Date ().timeIntervalSince1970))
// Unix timestamp of when activity occurred on device
// Code example shows how to retrieve current time in seconds
// Example value: "1484085154"
params[ "created_at_unix" ] = (System. currentTimeMillis () / 1000 ). toString ()
확률론적 모델링 데이터 포인트
확률론적 모델링을 어트리뷰션 방법으로 사용하려면 모든 서버 간 요청에 다음 파라미터를 포함해야 합니다.
파라미터 설명 device_name
기기의 이름 device_type
기기 유형 또는 모델 os_version
기기에서 실행되는 운영 체제의 버전 ip_address
디바이스의 IP 주소
Adjust는 특히 iOS에서 더욱 포괄적인 어트리뷰션이 가능하게 되므로 이러한 파라미터를 추가할 것을 강력히 추천합니다.
// Example value: "iPhone10,5"
var systemInfo = utsname ()
let machineMirror = Mirror ( reflecting : systemInfo.machine)
let deviceName = machineMirror.children. reduce ( "" ) {
guard let value = element. value as? Int8 , value != 0
else { return identifier }
return identifier + String ( UnicodeScalar ( UInt8 (value)))
params[ "device_name" ] = deviceName
// Example value: "iPhone"
params[ "device_type" ] = UIDevice.current.model
// Example value: "17.5.1"
params[ "os_version" ] = UIDevice.current.systemVersion
// Retrieve the device's IP address from requests to your server
params[ "ip_address" ] = "192.0.0.1" // Example value
import android.content.Context
import android.content.res.Configuration
import android.content.pm.PackageManager
val context: Context = // ... get your context here ...
val isGooglePlayGamesForPC = context.packageManager
. hasSystemFeature ( "com.google.android.play.feature
params[ "device_name" ] = if (isGooglePlayGamesForPC) null
params[ "os_version" ] = if (isGooglePlayGamesForPC) null
else Build.VERSION.RELEASE
params[ "device_type" ] = when {
isGooglePlayGamesForPC -> "pc"
(context.resources.configuration.uiMode and
Configuration.UI_MODE_TYPE_MASK) == Configuration
.UI_MODE_TYPE_TELEVISION -> "tv"
else -> when (context.resources.configuration.screenLayout
and Configuration.SCREENLAYOUT_SIZE_MASK) {
Configuration.SCREENLAYOUT_SIZE_SMALL,
Configuration.SCREENLAYOUT_SIZE_NORMAL -> "phone"
Configuration.SCREENLAYOUT_SIZE_LARGE,
Configuration.SCREENLAYOUT_SIZE_XLARGE -> "tablet"
// Retrieve the device's IP address from requests to
params[ "ip_address" ] = "192.0.0.1" // Example value
환경
environment
파라미터를 전달하여 요청이 전송되는 환경을 지정할 수 있습니다. 여러 환경으로부터의 요청은 테스트를 위해 Adjust에서 별도로 보관합니다. 다음 값을 사용할 수 있습니다.
sandbox
: 테스트 시 이를 사용하여 요청을 프로덕션 데이터와 분리합니다.
production
: 앱을 출시할 때 사용합니다.
이 파라미터를 전달하지 않으면 기본값은 production
입니다.
// For testing (sandbox environment)
params[ "environment" ] = "sandbox"
params[ "environment" ] = "production"
// For testing (sandbox environment)
params[ "environment" ] = "sandbox"
params[ "environment" ] = "production"
글로벌 콜백 파라미터
로 데이터 내보내기 를 사용하는 경우 모든 서버 간 요청에 ‘글로벌 콜백 파라미터’를 포함하여 로 데이터에 사용자 지정 파라미터를 추가할 수 있습니다. 이는 일반적으로 내보낸 로 데이터에 내부 사용자 ID를 포함하는 데 사용됩니다.
글로벌 콜백 파라미터는 문자열 키-값 쌍을 포함하는 JSON 객체로 표시됩니다.
params[ "callback_params" ] = '{ "user_id" : "2696775149" , "user_category" : "high value" }'
params[ "callback_params" ] = '{"user_id": "2696775149", "user_category": "high value"}'
글로벌 파트너 파라미터
특정 파트너와 연동하는 경우 모든 서버 간 요청에 ‘글로벌 파트너 파라미터’를 포함해야 할 수 있습니다. Adjust의 서버는 파트너에게 보내는 모든 콜백에서 이러한 파라미터를 전달합니다. 이는 일반적으로 수신하는 콜백에 고유한 사용자 ID를 요구하는 애널리틱스 파트너에 사용됩니다.
글로벌 파트너 파라미터는 문자열 키-값 쌍을 포함하는 JSON 객체로 표시됩니다.
params[ "partner_params" ] = '{ "analytics_user_id" : "3913132433" , "analytics_visitor_id" : "nzFC9LKSqM" }'
params[ "partner_params" ] = '{"analytics_user_id": "3913132433", "analytics_visitor_id": "nzFC9LKSqM"}'
요청
세션
세션은 Adjust 도입의 토대가 되며 유일한 필수 활동입니다. 세션은 일반적으로 앱이 실행되었음을 나타냅니다. Adjust 서버는 성공적인 세션 요청을 다음과 같이 기록합니다.
이는 기기의 첫 세션을 ‘설치’ 활동으로 기록합니다.
이후의 세션은 ‘세션’ 활동으로 기록됩니다.
리어트리뷰션 범주 가 충족되면 ‘리어트리뷰션’ 또는 ‘리어트리뷰션 재설치’ 활동을 기록합니다.
서버 간 세션 요청을 created_at_unix
파라미터와 함께 보낼 때 Adjust 서버에서 이 값은 마지막으로 성공적으로 기록된 세션의 created_at_unix
시간보다 최소 20분 이후여야 합니다.
curl -X POST "https://app.adjust.com/session" \ -H "Authorization: Bearer ADD_YOUR_AUTH_TOKEN_HERE" \
-H "Content-Type: application/x-www-form-urlencoded" \
&idfa=29DDE430-CE81-4F00-A50C-689595AAD142 \
&idfv=59E27F41-A86B-4560-B585-63161F871C4B \
&primary_dedupe_token=3b35fcfb-6115-4cff-830f-e32a248c487d \
&created_at_unix=1484085154 \
&device_name=iPhone16%2C2 \
&callback_params=%7B%22user_id%22%3A%20%222696775149%22%2C%20%22user_category%22%3A%20%22high%20value%22%7D \
&partner_params=%7B%22analytics_user_id%22%3A%20%223913132433%22%2C%20%22analytics_session_id%22%3A%20%22nzFC9LKSqM%22%7D" \
-w "\n\nHTTP Status Code: %{http_code}\n" \
이는 Adjust가 기기에 대한 첫 세션을 성공적으로 기록했을 때의 응답 형식입니다. 필요한 경우 Adjust의 테스팅 콘솔 을 사용하여 기기를 삭제하고 이를 여러 번 테스트할 수 있습니다.
"app_token": "4w565xzmb54d",
"adid": "df6c5653080670612cd2f9766ddc0814",
"timestamp": "2024-07-09T01:31:14.373Z+0000",
"message": "Install tracked",
이는 Adjust가 기기에 대한 이후 세션을 성공적으로 기록했을 때의 응답 형식입니다.
"app_token": "4w565xzmb54d",
"adid": "df6c5653080670612cd2f9766ddc0814",
"timestamp": "2024-07-09T02:31:14.373Z+0000",
"message": "Session tracked",
설치 후 이벤트
기기에 대해 최소 1회의 세션 요청이 성공적으로 전송되면 설치 후 이벤트 를 전송할 수 있습니다. 이는 일반적으로 마케팅 목표를 나타내는 이벤트로, 네트워크에서 캠페인을 최적화하는 데 사용할 수 있습니다.
// Add event token to existing params
params[ "event_token" ] = "2y7e81"
// Add revenue and currency, if applicable
// These parameters are equivalent to $19.99
params[ "revenue" ] = "19.99"
params[ "currency" ] = "USD"
// Add event token to existing params
params[ "event_token" ] = "2y7e81"
// Add revenue and currency, if applicable
// These parameters are equivalent to $19.99
params[ "revenue" ] = "19.99"
params[ "currency" ] = "USD"
콜백 파라미터
로 데이터 내보내기 를 사용하는 경우 이벤트 레벨 사용자 지정 데이터를 추가하기 위해 특정 이벤트 요청에 사용자 지정 ‘콜백 파라미터’를 포함할 수 있습니다. 구매 이벤트의 경우 해당 이벤트에 대한 로 데이터에 내부 트랜잭션 ID를 포함할 수 있습니다.
콜백 파라미터는 문자열 키-값 쌍을 포함하는 JSON 객체로 표시됩니다.
// If callback_params exists, add the event callback parameters to it (for example: txn_id)
params[ "callback_params" ] = '{ "user_id" : "2696775149" , "user_category" : "high value" , "txn_id" : "8837853376" }'
// If callback_params does not exist, create it
params[ "callback_params" ] = '{ "txn_id" : "8837853376" }'
// If callback_params exists, add the event callback parameters to it (for example: txn_id)
params[ "callback_params" ] = '{"user_id": "2696775149", "user_category": "high value", "txn_id": "8837853376"}'
// If callback_params does not exist, create it
params[ "callback_params" ] = '{"txn_id": "8837853376"}'
파트너 파라미터
특정 파트너와 연동하는 경우 이벤트 요청에 사용자 지정 ‘파트너 파라미터’를 포함해야 할 수 있습니다. Adjust의 서버는 해당 이벤트에 대해 파트너에게 보내는 콜백에 이러한 파라미터를 추가하게 됩니다. 이는 일반적으로 view_item
, add_to_cart
, 구매와 같은 이벤트에 대해 동적 리마케팅 캠페인을 활성화하는 데 주로 사용됩니다.
파트너 파라미터는 문자열 키-값 쌍을 포함하는 JSON 객체로 표시됩니다.
// If partner_params exists, add the event partner parameters to it (for example: item_id)
params[ "partner_params" ] = '{ "analytics_user_id" : "3913132433" , "analytics_session_id" : "nzFC9LKSqM" , "item_id" : "[ \" 76524 \" , \" 62599 \" ]" }'
// If partner_params does not exist, create it
params[ "partner_params" ] = '{ "item_id" : "[ \" 76524 \" , \" 62599 \" ]" }'
// If partner_params exists, add the event partner parameters to it (for example: item_id)
params[ "partner_params" ] = '{"analytics_user_id": "3913132433", "analytics_session_id": "nzFC9LKSqM", "item_id": "[ \" 76524 \" , \" 62599 \" ]"}'
// If partner_params does not exist, create it
params[ "partner_params" ] = '{"item_id": "[ \" 76524 \" , \" 62599 \" ]"}'
이벤트 요청을 전송합니다.
curl -X POST "https://app.adjust.com/event" \
-H "Authorization:Bearer ADD_YOUR_AUTH_TOKEN_HERE" \
-H "Content-Type:application/x-www-form-urlencoded" \
&idfa=29DDE430-CE81-4F00-A50C-689595AAD142 \
&idfv=59E27F41-A86B-4560-B585-63161F871C4B \
&primary_dedupe_token=3b35fcfb-6115-4cff-830f-e32a248c487d \
&created_at_unix=1484085154 \
&device_name=iPhone16%2C2 \
&callback_params=%7B%22user_id%22%3A%20%222696775149%22%2C%20%22user_category%22%3A%20%22high%20value%22%2C%20%22txn_id%22%3A%20%228837853376%22%7D \
&partner_params=%7B%22analytics_user_id%22%3A%20%223913132433%22%2C%20%22analytics_session_id%22%3A%20%22nzFC9LKSqM%22%2C%20%22item_id%22%3A%20%22%5B%5C%2276524%5C%22%2C%5C%2262599%5C%22%5D%22%7D" \
-w "\n\nHTTP Status Code: %{http_code}\n" \