StageUp
Mobile SDKDeep Link

Android

AdStage In-App Event Integration Guide (Android)

Table of Contents

  1. Overview
  2. Basic Setup
  3. Basic Event Tracking
  4. Advanced Event Tracking
  5. User and Device Information
  6. Event Type Examples
  7. Best Practices
  8. Troubleshooting

Overview

AdStage in-app events track user behavior and app events to support marketing analysis and optimization.

Key Features

  • Flexible Event Tracking: From simple calls to detailed context
  • Automatic Context Collection: Device information and user properties automatically included
  • Session Management: Automatic session tracking and management
  • Builder Pattern: High-readability DSL style support
  • Asynchronous Processing: Coroutine-based suspend functions
  • Offline Support: Automatic retry when network reconnects

Basic Setup

1. Add Gradle Dependencies

settings.gradle.kts

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://repo.nbase.io/repository/nbase-releases") }
    }
}

build.gradle.kts (Module: app)

dependencies {
    implementation("io.nbase:nbase-adapter-adstage:3.0.5")
    
    // Required dependencies
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
    implementation("com.squareup.okhttp3:okhttp:4.11.0")
}

2. SDK Initialization

import io.nbase.adapter.adstage.AdStageManager
 
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        // Initialize AdStage
        AdStageManager.initialize(
            context = this,
            apiKey = "your-api-key-here",
            serverUrl = "https://api.adstage.app"
        )
        
        Log.d("AdStage", "✅ SDK initialization complete")
    }
}

3. AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
    <!-- Required permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">
        
        <!-- ... -->
        
    </application>
</manifest>

Type-Safe Event Tracking

1. Simplest Approach

import io.nbase.adapter.adstage.AdStageManager
import io.nbase.adapter.adstage.models.AdStageEvent
 
// Event without parameters
AdStageManager.trackEvent(AdStageEvent.FirstOpen())
 
// Login event
AdStageManager.trackEvent(
    AdStageEvent.Login(method = SignUpMethod.EMAIL)
)

2. Purchase Event (Validation Example)

// ✅ GOOD: Provide value and currency together
AdStageManager.trackEvent(
    AdStageEvent.Purchase(
        value = 29.99,
        currency = "USD",
        transactionId = "TXN_123456"
    )
)
 
// ❌ BAD: Compile error when only value is provided!
AdStageManager.trackEvent(
    AdStageEvent.Purchase(
        value = 29.99  // ❌ Error: currency required!
    )
)
 
// ✅ GOOD: Only transactionId without currency
AdStageManager.trackEvent(
    AdStageEvent.Purchase(
        transactionId = "TXN_123456"
    )
)

3. Product View

// With parameters
AdStageManager.trackEvent(
    AdStageEvent.ProductDetailsView(
        itemId = "PROD_123",
        itemName = "Wireless Earbuds"
    )
)
 
// Without parameters
AdStageManager.trackEvent(AdStageEvent.ProductListView())

4. Custom Events (event_name Auto-Promotion)

For sending app-specific events beyond standard events, use AdStageEvent.Custom. When you include the event_name key in parameters, that value is automatically promoted as the actual event name and stored in the dashboard.

// Example: Send a custom event named 'promotion_click'
AdStageManager.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "event_name" to "promotion_click",
            "promotion_id" to "summer_sale_2025",
            "screen" to "home_banner"
        )
    )
)
// Collected as "promotion_click" event in dashboard
 
// General custom event without event_name
AdStageManager.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "action" to "button_click",
            "button_id" to "promo_banner",
            "screen" to "home",
            "timestamp" to System.currentTimeMillis()
        )
    )
)
// Collected as "custom" event in dashboard
 
// Click and View also support free parameters
AdStageManager.trackEvent(
    AdStageEvent.Click(
        params = mapOf(
            "campaign_id" to "SUMMER2025",
            "ad_group" to "electronics"
        )
    )
)

Standard Event Catalog

The AdStage SDK provides 46 standard events.

📌 Ad Tracking (4 events)

// 1. Ad Click
AdStageManager.trackEvent(
    AdStageEvent.Click(
        params = mapOf("campaign_id" to "CAMP_123")
    )
)
 
// 2. Ad Impression
AdStageManager.trackEvent(
    AdStageEvent.View(
        params = mapOf("impression_id" to "IMP_456")
    )
)
 
// 3. App Install
AdStageManager.trackEvent(AdStageEvent.Install())
 
// 4. Custom Event (specify event name with event_name)
AdStageManager.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "event_name" to "promotion_click",
            "promotion_id" to "summer_sale_2025"
        )
    )
)

👤 User Lifecycle (5 events)

// SignUpMethod enum
enum class SignUpMethod(val value: String) {
    EMAIL("email"),
    GOOGLE("google"),
    APPLE("apple"),
    FACEBOOK("facebook"),
    KAKAO("kakao"),
    NAVER("naver")
}
 
// 1. Sign Up Complete
AdStageManager.trackEvent(
    AdStageEvent.SignUp(method = SignUpMethod.GOOGLE)
)
 
// 2. Sign Up Start
AdStageManager.trackEvent(AdStageEvent.SignUpStart())
 
// 3. Login
AdStageManager.trackEvent(
    AdStageEvent.Login(method = SignUpMethod.EMAIL)
)
 
// 4. Logout
AdStageManager.trackEvent(AdStageEvent.Logout())
 
// 5. First App Open
AdStageManager.trackEvent(AdStageEvent.FirstOpen())

📄 Content Views (6 events)

// 1. Home Screen
AdStageManager.trackEvent(AdStageEvent.HomeView())
 
// 2. Product List
AdStageManager.trackEvent(
    AdStageEvent.ProductListView(itemCategory = "electronics")
)
 
// 3. Search Results
AdStageManager.trackEvent(
    AdStageEvent.SearchResultView(searchTerm = "wireless headphones")
)
 
// 4. Product Details
AdStageManager.trackEvent(
    AdStageEvent.ProductDetailsView(
        itemId = "PROD_123",
        itemName = "Wireless Earbuds"
    )
)
 
// 5. Page View (Web)
AdStageManager.trackEvent(
    AdStageEvent.PageView(
        pageUrl = "https://example.com/products",
        pageTitle = "Products"
    )
)
 
// 6. Screen View (App)
AdStageManager.trackEvent(
    AdStageEvent.ScreenView(
        screenName = "product_detail",
        screenClass = "ProductDetailActivity"
    )
)

🛒 E-commerce (8 events)

// 1. Add to Cart
AdStageManager.trackEvent(
    AdStageEvent.AddToCart(
        value = 99000.0,
        currency = "KRW",
        items = listOf(
            EcommerceItem(
                itemId = "PROD_123",
                itemName = "Wireless Earbuds",
                price = 99000.0,
                quantity = 1
            )
        )
    )
)
 
// 2. Remove from Cart
AdStageManager.trackEvent(
    AdStageEvent.RemoveFromCart(
        value = 50000.0,
        currency = "KRW"
    )
)
 
// 3. Add to Wishlist
AdStageManager.trackEvent(
    AdStageEvent.AddToWishlist(
        itemId = "PROD_456",
        itemName = "Smart Watch"
    )
)
 
// 4. Add Payment Info
AdStageManager.trackEvent(
    AdStageEvent.AddPaymentInfo(paymentType = "credit_card")
)
 
// 5. Begin Checkout
AdStageManager.trackEvent(
    AdStageEvent.BeginCheckout(
        value = 150000.0,
        currency = "KRW"
    )
)
 
// 6. Purchase Complete ⭐⭐⭐
AdStageManager.trackEvent(
    AdStageEvent.Purchase(
        value = 129000.0,
        currency = "KRW",
        transactionId = "ORDER_20250105_001",
        tax = 12900.0,
        shipping = 3000.0,
        coupon = "SUMMER2025",
        items = listOf(
            EcommerceItem(
                itemId = "PROD_123",
                itemName = "Wireless Earbuds",
                itemCategory = "electronics",
                price = 126000.0,
                quantity = 1
            )
        )
    )
)
 
// 7. Refund
AdStageManager.trackEvent(
    AdStageEvent.Refund(
        transactionId = "ORDER_20250105_001",
        value = 129000.0,
        currency = "KRW"
    )
)

🎮 Progress/Achievement (4 events)

// 1. Tutorial Begin
AdStageManager.trackEvent(
    AdStageEvent.TutorialBegin(
        params = mapOf("tutorial_id" to "intro")
    )
)
 
// 2. Tutorial Complete
AdStageManager.trackEvent(
    AdStageEvent.TutorialComplete(
        params = mapOf("duration_seconds" to 120)
    )
)
 
// 3. Level Up
AdStageManager.trackEvent(
    AdStageEvent.LevelUp(
        level = 25,
        character = "warrior"
    )
)
 
// 4. Achievement Unlocked
AdStageManager.trackEvent(
    AdStageEvent.Achievement(achievementId = "first_win")
)

💬 Interactions (3 events)

// 1. Search
AdStageManager.trackEvent(
    AdStageEvent.Search(searchTerm = "gaming laptop")
)
 
// 2. Share
AdStageManager.trackEvent(
    AdStageEvent.Share(
        contentType = "product",
        itemId = "PROD_789",
        method = "kakao"
    )
)
 
// 3. Ad Click
AdStageManager.trackEvent(
    AdStageEvent.AdClick(adId = "AD_12345")
)

🎮 Gaming Specific (4 events)

// 1. Game Play
AdStageManager.trackEvent(
    AdStageEvent.GamePlay(
        level = 10,
        levelName = "Dragon's Lair",
        character = "mage",
        contentType = "dungeon"
    )
)
 
// 2. Acquire Bonus
AdStageManager.trackEvent(
    AdStageEvent.AcquireBonus(
        contentType = "reward",
        itemId = "ITEM_123",
        itemName = "Gold Chest",
        quantity = 1
    )
)
 
// 3. Select Game Server
AdStageManager.trackEvent(
    AdStageEvent.SelectGameServer(
        contentId = "SERVER_01",
        contentType = "pvp",
        itemName = "Asia Server"
    )
)
 
// 4. Patch Complete
AdStageManager.trackEvent(
    AdStageEvent.CompletePatch(
        contentId = "PATCH_2.1.0",
        contentType = "update"
    )
)

📅 Subscription/Trial (3 events)

// 1. Start Trial
AdStageManager.trackEvent(
    AdStageEvent.StartTrial(
        value = 9900.0,
        currency = "KRW",
        trialDays = 14
    )
)
 
// 2. Subscribe
AdStageManager.trackEvent(
    AdStageEvent.Subscribe(
        value = 9900.0,
        currency = "KRW",
        subscriptionId = "premium_monthly"
    )
)
 
// 3. Unsubscribe
AdStageManager.trackEvent(
    AdStageEvent.Unsubscribe(subscriptionId = "premium_monthly")
)

💰 Virtual Currency (2 events)

// 1. Earn Virtual Currency
AdStageManager.trackEvent(
    AdStageEvent.EarnVirtualCurrency(
        virtualCurrencyName = "gold",
        value = 500.0
    )
)
 
// 2. Spend Virtual Currency
AdStageManager.trackEvent(
    AdStageEvent.SpendVirtualCurrency(
        virtualCurrencyName = "gold",
        value = 100.0,
        itemName = "health_potion"
    )
)

🎯 Miscellaneous (7 events)

// 1. Schedule
AdStageManager.trackEvent(
    AdStageEvent.Schedule(
        params = mapOf("event_type" to "appointment")
    )
)
 
// 2. Spend Credits
AdStageManager.trackEvent(
    AdStageEvent.SpendCredits(
        value = 10.0,
        itemName = "premium_feature"
    )
)
 
// 3. View Promotion
AdStageManager.trackEvent(
    AdStageEvent.ViewPromotion(
        promotionId = "PROMO_SUMMER",
        promotionName = "Summer Sale 2025",
        creativeSlot = "home_banner_1"
    )
)
 
// 4. Select Promotion
AdStageManager.trackEvent(
    AdStageEvent.SelectPromotion(
        promotionId = "PROMO_SUMMER",
        promotionName = "Summer Sale 2025"
    )
)

Event Type Examples

1. App Lifecycle

class MyApplication : Application() {
    
    override fun onCreate() {
        super.onCreate()
        
        // Initialize SDK
        AdStageManager.initialize(this, apiKey, serverUrl)
        
        // First open event is sent automatically by SDK
        Log.d("App", "✅ App started")
    }
}

2. User Authentication

class AuthManager {
    
    // Sign Up
    fun onSignUpComplete(method: String) {
        val signUpMethod = when(method) {
            "email" -> SignUpMethod.EMAIL
            "google" -> SignUpMethod.GOOGLE
            "apple" -> SignUpMethod.APPLE
            "kakao" -> SignUpMethod.KAKAO
            "naver" -> SignUpMethod.NAVER
            else -> SignUpMethod.EMAIL
        }
        
        AdStageManager.trackEvent(
            AdStageEvent.SignUp(method = signUpMethod)
        )
        
        Log.d("Auth", "✅ Sign up complete: $method")
    }
    
    // Login
    fun onLoginSuccess(userId: String, method: String) {
        val loginMethod = when(method) {
            "email" -> SignUpMethod.EMAIL
            "google" -> SignUpMethod.GOOGLE
            else -> SignUpMethod.EMAIL
        }
        
        AdStageManager.trackEvent(
            AdStageEvent.Login(method = loginMethod)
        )
        
        Log.d("Auth", "✅ Login: $userId")
    }
    
    // Logout
    fun onLogout() {
        AdStageManager.trackEvent(AdStageEvent.Logout())
        Log.d("Auth", "🚪 Logout")
    }
}

3. Screen Tracking (BaseActivity Pattern)

abstract class BaseActivity : AppCompatActivity() {
    
    override fun onResume() {
        super.onResume()
        trackScreenView()
    }
    
    abstract fun getScreenName(): String
    
    private fun trackScreenView() {
        AdStageManager.trackEvent(
            AdStageEvent.ScreenView(
                screenName = getScreenName(),
                screenClass = this::class.java.simpleName
            )
        )
        
        Log.d("Screen", "📺 ${getScreenName()}")
    }
}
 
// Usage example
class HomeActivity : BaseActivity() {
    override fun getScreenName() = "home"
}
 
class ProductDetailActivity : BaseActivity() {
    override fun getScreenName() = "product_detail"
    
    private fun loadProduct(productId: String) {
        // Load product data...
        
        // Product detail view event
        AdStageManager.trackEvent(
            AdStageEvent.ProductDetailsView(
                itemId = productId,
                itemName = product.name
            )
        )
    }
}

4. Complete E-commerce Flow

class EcommerceManager {
    
    // 1. Product List View
    fun trackProductList(category: String) {
        AdStageManager.trackEvent(
            AdStageEvent.ProductListView(itemCategory = category)
        )
    }
    
    // 2. Search
    fun trackSearch(query: String) {
        AdStageManager.trackEvent(
            AdStageEvent.Search(searchTerm = query)
        )
    }
    
    // 3. Search Results View
    fun trackSearchResults(query: String) {
        AdStageManager.trackEvent(
            AdStageEvent.SearchResultView(searchTerm = query)
        )
    }
    
    // 4. Product Detail View
    fun trackProductView(product: Product) {
        AdStageManager.trackEvent(
            AdStageEvent.ProductDetailsView(
                itemId = product.id,
                itemName = product.name
            )
        )
    }
    
    // 5. Add to Cart
    fun trackAddToCart(product: Product, quantity: Int) {
        val item = EcommerceItem(
            itemId = product.id,
            itemName = product.name,
            itemCategory = product.category,
            price = product.price,
            quantity = quantity
        )
        
        AdStageManager.trackEvent(
            AdStageEvent.AddToCart(
                value = product.price * quantity,
                currency = "KRW",
                items = listOf(item)
            )
        )
    }
    
    // 6. Add to Wishlist
    fun trackAddToWishlist(product: Product) {
        AdStageManager.trackEvent(
            AdStageEvent.AddToWishlist(
                itemId = product.id,
                itemName = product.name
            )
        )
    }
    
    // 7. Begin Checkout
    fun trackBeginCheckout(cart: Cart) {
        val items = cart.items.map { cartItem ->
            EcommerceItem(
                itemId = cartItem.product.id,
                itemName = cartItem.product.name,
                itemCategory = cartItem.product.category,
                price = cartItem.product.price,
                quantity = cartItem.quantity
            )
        }
        
        AdStageManager.trackEvent(
            AdStageEvent.BeginCheckout(
                value = cart.totalAmount,
                currency = "KRW",
                items = items
            )
        )
    }
    
    // 8. Add Payment Info
    fun trackAddPaymentInfo(paymentMethod: String) {
        AdStageManager.trackEvent(
            AdStageEvent.AddPaymentInfo(paymentType = paymentMethod)
        )
    }
    
    // 9. Purchase Complete ⭐⭐⭐
    fun trackPurchase(order: Order) {
        val items = order.items.map { orderItem ->
            EcommerceItem(
                itemId = orderItem.product.id,
                itemName = orderItem.product.name,
                itemCategory = orderItem.product.category,
                price = orderItem.product.price,
                quantity = orderItem.quantity
            )
        }
        
        AdStageManager.trackEvent(
            AdStageEvent.Purchase(
                value = order.totalAmount,
                currency = "KRW",
                transactionId = order.id,
                tax = order.tax,
                shipping = order.shippingFee,
                coupon = order.couponCode,
                items = items
            )
        )
        
        Log.d("Ecommerce", "✅ Purchase complete: ${order.id}, ${order.totalAmount} KRW")
    }
    
    // 10. Refund
    fun trackRefund(order: Order) {
        AdStageManager.trackEvent(
            AdStageEvent.Refund(
                transactionId = order.id,
                value = order.totalAmount,
                currency = "KRW"
            )
        )
    }
    
    // 11. Share
    fun trackShare(product: Product, method: String) {
        AdStageManager.trackEvent(
            AdStageEvent.Share(
                contentType = "product",
                itemId = product.id,
                method = method
            )
        )
    }
}

5. Game Events

class GameEventManager {
    
    // Tutorial
    fun trackTutorialBegin(tutorialId: String) {
        AdStageManager.trackEvent(
            AdStageEvent.TutorialBegin(
                params = mapOf("tutorial_id" to tutorialId)
            )
        )
    }
    
    fun trackTutorialComplete(tutorialId: String, duration: Long) {
        AdStageManager.trackEvent(
            AdStageEvent.TutorialComplete(
                params = mapOf(
                    "tutorial_id" to tutorialId,
                    "duration_seconds" to duration / 1000
                )
            )
        )
    }
    
    // Level
    fun trackLevelUp(level: Int, character: String) {
        AdStageManager.trackEvent(
            AdStageEvent.LevelUp(
                level = level,
                character = character
            )
        )
    }
    
    // Achievement
    fun trackAchievement(achievementId: String) {
        AdStageManager.trackEvent(
            AdStageEvent.Achievement(achievementId = achievementId)
        )
    }
    
    // Game Play
    fun trackGameStart(level: Int, levelName: String, character: String) {
        AdStageManager.trackEvent(
            AdStageEvent.GamePlay(
                level = level,
                levelName = levelName,
                character = character,
                contentType = "pvp"
            )
        )
    }
    
    // Bonus Acquired
    fun trackBonusAcquired(itemId: String, itemName: String, quantity: Int) {
        AdStageManager.trackEvent(
            AdStageEvent.AcquireBonus(
                contentType = "reward",
                itemId = itemId,
                itemName = itemName,
                quantity = quantity
            )
        )
    }
    
    // Virtual Currency
    fun trackEarnCurrency(currencyName: String, amount: Double) {
        AdStageManager.trackEvent(
            AdStageEvent.EarnVirtualCurrency(
                virtualCurrencyName = currencyName,
                value = amount
            )
        )
    }
    
    fun trackSpendCurrency(currencyName: String, amount: Double, itemName: String) {
        AdStageManager.trackEvent(
            AdStageEvent.SpendVirtualCurrency(
                virtualCurrencyName = currencyName,
                value = amount,
                itemName = itemName
            )
        )
    }
}

Best Practices

1. Using Extension Functions

// ActivityExtensions.kt
fun Activity.trackScreen() {
    val screenName = this::class.java.simpleName
        .removeSuffix("Activity")
        .lowercase()
    
    AdStageManager.trackEvent(
        AdStageEvent.ScreenView(
            screenName = screenName,
            screenClass = this::class.java.simpleName
        )
    )
}
 
// Usage
class ProfileActivity : AppCompatActivity() {
    override fun onResume() {
        super.onResume()
        trackScreen()  // ✅ Simple!
    }
}

2. Event Tracking in ViewModel

class ProductViewModel : ViewModel() {
    
    private val _productState = MutableLiveData<Product>()
    val productState: LiveData<Product> = _productState
    
    fun loadProduct(productId: String) {
        viewModelScope.launch {
            try {
                val product = repository.getProduct(productId)
                _productState.value = product
                
                // Product view event
                AdStageManager.trackEvent(
                    AdStageEvent.ProductDetailsView(
                        itemId = product.id,
                        itemName = product.name
                    )
                )
                
            } catch (e: Exception) {
                Log.e("ProductVM", "Failed to load product", e)
            }
        }
    }
    
    fun addToCart(product: Product, quantity: Int) {
        viewModelScope.launch {
            try {
                repository.addToCart(product, quantity)
                
                val item = EcommerceItem(
                    itemId = product.id,
                    itemName = product.name,
                    price = product.price,
                    quantity = quantity
                )
                
                AdStageManager.trackEvent(
                    AdStageEvent.AddToCart(
                        value = product.price * quantity,
                        currency = "KRW",
                        items = listOf(item)
                    )
                )
                
            } catch (e: Exception) {
                Log.e("ProductVM", "Failed to add to cart", e)
            }
        }
    }
}

3. Using with Compose UI

@Composable
fun ProductDetailScreen(
    productId: String,
    viewModel: ProductViewModel = hiltViewModel()
) {
    val product by viewModel.productState.collectAsState()
    
    // Event on screen entry
    LaunchedEffect(productId) {
        viewModel.loadProduct(productId)
        
        AdStageManager.trackEvent(
            AdStageEvent.ScreenView(
                screenName = "product_detail",
                screenClass = "ProductDetailScreen"
            )
        )
    }
    
    Column {
        // UI...
        
        Button(
            onClick = {
                viewModel.addToCart(product, 1)
                
                AdStageManager.trackEvent(
                    AdStageEvent.Custom(
                        params = mapOf(
                            "action" to "add_to_cart_button",
                            "product_id" to product.id
                        )
                    )
                )
            }
        ) {
            Text("Add to Cart")
        }
    }
}

4. Event Wrapper Class

object AnalyticsManager {
    
    private const val TAG = "Analytics"
    
    fun trackScreen(screenName: String, screenClass: String? = null) {
        AdStageManager.trackEvent(
            AdStageEvent.ScreenView(
                screenName = screenName,
                screenClass = screenClass
            )
        )
        Log.d(TAG, "📺 Screen: $screenName")
    }
    
    fun trackPurchase(order: Order) {
        val items = order.items.map {
            EcommerceItem(
                itemId = it.product.id,
                itemName = it.product.name,
                price = it.product.price,
                quantity = it.quantity
            )
        }
        
        AdStageManager.trackEvent(
            AdStageEvent.Purchase(
                value = order.totalAmount,
                currency = "KRW",
                transactionId = order.id,
                items = items
            )
        )
        
        Log.d(TAG, "💰 Purchase: ${order.id}")
    }
    
    fun trackError(error: Throwable, context: String) {
        AdStageManager.trackEvent(
            AdStageEvent.Custom(
                params = mapOf(
                    "event_type" to "error",
                    "error_message" to (error.message ?: "unknown"),
                    "context" to context
                )
            )
        )
        Log.e(TAG, "❌ Error: $context", error)
    }
}

5. Performance Optimization: Throttling

class ThrottledEventTracker {
    private val lastTrackTimes = mutableMapOf<String, Long>()
    private val throttleInterval = 2000L  // 2 seconds
    
    fun trackEvent(event: AdStageEvent) {
        val eventKey = event.eventName
        val now = System.currentTimeMillis()
        val lastTime = lastTrackTimes[eventKey] ?: 0L
        
        if (now - lastTime >= throttleInterval) {
            AdStageManager.trackEvent(event)
            lastTrackTimes[eventKey] = now
        } else {
            Log.d("AdStage", "⏱️ Throttled: $eventKey")
        }
    }
}
 
// Usage (scroll events, etc.)
val throttledTracker = ThrottledEventTracker()
 
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        throttledTracker.trackEvent(
            AdStageEvent.Custom(
                params = mapOf(
                    "action" to "scroll",
                    "delta_y" to dy
                )
            )
        )
    }
})

Conversion Examples

// 1. Basic event
AdStage.trackEvent("first_open")
→ AdStageManager.trackEvent(AdStageEvent.FirstOpen())
 
// 2. Login
AdStage.trackEvent("login", mapOf("method" to "email"))
→ AdStageManager.trackEvent(AdStageEvent.Login(method = SignUpMethod.EMAIL))
 
// 3. Screen view
AdStage.trackEvent("screen_view", mapOf("screen_name" to "home"))
→ AdStageManager.trackEvent(AdStageEvent.ScreenView(screenName = "home"))
 
// 4. Custom
AdStage.trackEvent("custom", mapOf("action" to "click"))
→ AdStageManager.trackEvent(AdStageEvent.Custom(params = mapOf("action" to "click")))

Troubleshooting

1. Compile Error: "currency parameter required"

Problem:

// ❌ Error
AdStageManager.trackEvent(
    AdStageEvent.Purchase(value = 9900.0)
)

Solution:

// ✅ Add currency (ISO 4217, 3-letter)
AdStageManager.trackEvent(
    AdStageEvent.Purchase(
        value = 9900.0,
        currency = "KRW"
    )
)

2. IDE Auto-complete Not Working

Solution:

  1. Gradle Sync: File → Sync Project with Gradle Files
  2. Invalidate Caches: File → Invalidate Caches / Restart...
  3. Check Import:
import io.nbase.adapter.adstage.models.AdStageEvent.*
 
// Now auto-complete works
AdStageManager.trackEvent(Purchase(...))

3. ProGuard/R8 Obfuscation Issues

# proguard-rules.pro

# Preserve AdStage event models
-keep class io.nbase.adapter.adstage.models.** { *; }
-keepclassmembers class io.nbase.adapter.adstage.models.** { *; }

# AdStageEvent sealed class
-keep class io.nbase.adapter.adstage.models.AdStageEvent { *; }
-keep class io.nbase.adapter.adstage.models.AdStageEvent$* { *; }

# Kotlin Metadata
-keep class kotlin.Metadata { *; }

4. Currency Code Validation Error

// ❌ 2-letter code
AdStageEvent.Purchase(value = 100.0, currency = "KR")
// ValidationException: "Currency must be 3-letter ISO 4217 code"
 
// ✅ 3-letter ISO 4217 code
AdStageEvent.Purchase(value = 100.0, currency = "KRW")  // Korean Won
AdStageEvent.Purchase(value = 100.0, currency = "USD")  // US Dollar
AdStageEvent.Purchase(value = 100.0, currency = "JPY")  // Japanese Yen

Major Currency Codes:

CountryCurrencyCode
South KoreaWonKRW
United StatesDollarUSD
JapanYenJPY
European UnionEuroEUR
United KingdomPoundGBP

5. Check Debug Logs

// Application.onCreate()
if (BuildConfig.DEBUG) {
    AdStageManager.setDebugMode(true)
}

Logcat Filter:

# Android Studio
tag:AdStage OR tag:AdapterAdStage
 
# adb
adb logcat | grep -i adstage

Reference

Standards Reference


FAQ

Q: How do I send custom events?
A: Use AdStageEvent.Custom(params = mapOf(...))

Q: Can I use currency without value?
A: No, currency is required when using value.

Q: Does it work offline?
A: Yes, the SDK automatically queues events and sends them when network is restored.


Support

Contact:


© 2025 NBase. All rights reserved.

Table of Contents