StageUp
Mobile SDKDeep Link

iOS

AdStage In-App Event Integration Guide (iOS)

Table of Contents

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

Overview

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

Key Features

  • Global Context Management: Set user/device information once and it's automatically included
  • Simple API: Easy to send with just event name and parameters
  • Automatic Session Tracking: Automatic session ID generation and management
  • Asynchronous Processing: Network communication doesn't block UI
  • Offline Support: Automatic retry when network is restored

Basic Setup

CocoaPods Configuration

Podfile

platform :ios, '12.0'
 
target 'YourApp' do
  use_frameworks!
  
  # AdStage SDK
  pod 'AdapterAdStage', '3.0.5'
  
  # Dependencies (automatically installed)
  # Alamofire, SwiftyJSON, etc.
end
 
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
    end
  end
end

Installation:

pod install

2. SDK Initialization

import AdapterAdStage
 
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // Initialize AdStage
        AdStageManager.shared.initialize(
            apiKey: "your-api-key-here",
            serverUrl: "https://api.adstage.app"
        )
        
        print("✅ AdStage SDK initialization complete")
        
        return true
    }
}

3. Info.plist Configuration

<!-- Network permission -->
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>

Type-Safe Event Tracking

1. Simplest Approach

import AdapterAdStage
 
// Event without parameters
AdStageManager.shared.trackEvent(AdStageEvent.FirstOpen())
 
// Login event
AdStageManager.shared.trackEvent(
    AdStageEvent.Login(method: .email)
)

2. Purchase Event (Validation Example)

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

3. Product View

// With parameters
AdStageManager.shared.trackEvent(
    AdStageEvent.ProductDetailsView(
        itemId: "PROD_123",
        itemName: "Wireless Earbuds"
    )
)
 
// Without parameters
AdStageManager.shared.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.shared.trackEvent(
    AdStageEvent.Custom(
        params: [
            "event_name": "promotion_click",
            "promotion_id": "summer_sale_2025",
            "screen": "home_banner"
        ]
    )
)
// Collected as "promotion_click" event in dashboard
 
// General custom event without event_name
AdStageManager.shared.trackEvent(
    AdStageEvent.Custom(
        params: [
            "action": "button_click",
            "button_id": "promo_banner",
            "screen": "home",
            "timestamp": Date().timeIntervalSince1970
        ]
    )
)
// Collected as "custom" event in dashboard
 
// Click and View also support free parameters
AdStageManager.shared.trackEvent(
    AdStageEvent.Click(
        params: [
            "campaign_id": "SUMMER2025",
            "ad_group": "electronics"
        ]
    )
)

Standard Event Catalog

The AdStage SDK provides 46 standard events.

📌 Ad Tracking (4 events)

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

👤 User Lifecycle (5 events)

// SignUpMethod enum
public enum SignUpMethod: String {
    case email = "email"
    case google = "google"
    case apple = "apple"
    case facebook = "facebook"
    case kakao = "kakao"
    case naver = "naver"
}
 
// 1. Sign Up Complete
AdStageManager.shared.trackEvent(
    AdStageEvent.SignUp(method: .google)
)
 
// 2. Sign Up Start
AdStageManager.shared.trackEvent(AdStageEvent.SignUpStart())
 
// 3. Login
AdStageManager.shared.trackEvent(
    AdStageEvent.Login(method: .email)
)
 
// 4. Logout
AdStageManager.shared.trackEvent(AdStageEvent.Logout())
 
// 5. First App Open
AdStageManager.shared.trackEvent(AdStageEvent.FirstOpen())

📄 Content Views (6 events)

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

🛒 E-commerce (8 events)

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

🎮 Progress/Achievement (4 events)

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

💬 Interactions (3 events)

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

🎮 Gaming Specific (4 events)

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

📅 Subscription/Trial (3 events)

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

💰 Virtual Currency (2 events)

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

🎯 Miscellaneous (7 events)

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

Event Type Examples

1. App Lifecycle

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // Initialize SDK
        AdStageManager.shared.initialize(
            apiKey: "your-api-key",
            serverUrl: "https://api.adstage.app"
        )
        
        // First open event is sent automatically by SDK
        print("✅ App started")
        
        return true
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        print("📱 App entered background")
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        print("📱 App entered foreground")
    }
}

2. User Authentication

class AuthManager {
    
    // Sign Up
    func onSignUpComplete(method: String) {
        let signUpMethod: SignUpMethod
        switch method {
        case "email": signUpMethod = .email
        case "google": signUpMethod = .google
        case "apple": signUpMethod = .apple
        case "kakao": signUpMethod = .kakao
        case "naver": signUpMethod = .naver
        default: signUpMethod = .email
        }
        
        AdStageManager.shared.trackEvent(
            AdStageEvent.SignUp(method: signUpMethod)
        )
        
        print("✅ Sign up complete: \(method)")
    }
    
    // Login
    func onLoginSuccess(userId: String, method: String) {
        let loginMethod: SignUpMethod = method == "google" ? .google : .email
        
        AdStageManager.shared.trackEvent(
            AdStageEvent.Login(method: loginMethod)
        )
        
        print("✅ Login: \(userId)")
    }
    
    // Logout
    func onLogout() {
        AdStageManager.shared.trackEvent(AdStageEvent.Logout())
        print("🚪 Logout")
    }
}

3. Screen Tracking (BaseViewController Pattern)

class BaseViewController: UIViewController {
    
    // Override in subclasses
    var screenName: String {
        return String(describing: type(of: self))
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        trackScreenView()
    }
    
    private func trackScreenView() {
        AdStageManager.shared.trackEvent(
            AdStageEvent.ScreenView(
                screenName: screenName,
                screenClass: String(describing: type(of: self))
            )
        )
        
        print("📺 \(screenName)")
    }
}
 
// Usage example
class HomeViewController: BaseViewController {
    override var screenName: String { "home" }
}
 
class ProductDetailViewController: BaseViewController {
    override var screenName: String { "product_detail" }
    var productId: String?
    
    func loadProduct(_ productId: String) {
        self.productId = productId
        // Load data...
        
        // Product detail view event
        AdStageManager.shared.trackEvent(
            AdStageEvent.ProductDetailsView(
                itemId: productId,
                itemName: product.name
            )
        )
    }
}

4. Complete E-commerce Flow

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

5. Game Events

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

Best Practices

1. Using Extensions

// UIViewController+AdStage.swift
extension UIViewController {
    func trackScreen() {
        let screenName = String(describing: type(of: self))
            .replacingOccurrences(of: "ViewController", with: "")
            .lowercased()
        
        AdStageManager.shared.trackEvent(
            AdStageEvent.ScreenView(
                screenName: screenName,
                screenClass: String(describing: type(of: self))
            )
        )
    }
}
 
// Usage
class ProfileViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        trackScreen()  // ✅ Simple!
    }
}

2. Event Tracking in ViewModel

class ProductViewModel: ObservableObject {
    
    @Published var product: Product?
    
    func loadProduct(productId: String) {
        Task {
            do {
                let product = try await repository.getProduct(productId)
                self.product = product
                
                // Product view event
                AdStageManager.shared.trackEvent(
                    AdStageEvent.ProductDetailsView(
                        itemId: product.id,
                        itemName: product.name
                    )
                )
                
            } catch {
                print("Failed to load product: \(error)")
            }
        }
    }
    
    func addToCart(product: Product, quantity: Int) {
        Task {
            do {
                try await repository.addToCart(product, quantity: quantity)
                
                let item = EcommerceItem(
                    itemId: product.id,
                    itemName: product.name,
                    price: product.price,
                    quantity: quantity
                )
                
                AdStageManager.shared.trackEvent(
                    AdStageEvent.AddToCart(
                        value: product.price * Double(quantity),
                        currency: "KRW",
                        items: [item]
                    )
                )
                
            } catch {
                print("Failed to add to cart: \(error)")
            }
        }
    }
}

3. Using with SwiftUI

import SwiftUI
import AdapterAdStage
 
struct ProductDetailView: View {
    let productId: String
    @StateObject private var viewModel = ProductViewModel()
    
    var body: some View {
        VStack {
            // UI...
            
            Button("Add to Cart") {
                viewModel.addToCart(viewModel.product, quantity: 1)
                
                // Button click event
                AdStageManager.shared.trackEvent(
                    AdStageEvent.Custom(
                        params: [
                            "action": "add_to_cart_button",
                            "product_id": productId
                        ]
                    )
                )
            }
        }
        .onAppear {
            viewModel.loadProduct(productId: productId)
            
            // Screen view event
            AdStageManager.shared.trackEvent(
                AdStageEvent.ScreenView(
                    screenName: "product_detail",
                    screenClass: "ProductDetailView"
                )
            )
        }
    }
}

4. Event Wrapper Class

class AnalyticsManager {
    
    static let shared = AnalyticsManager()
    private init() {}
    
    func trackScreen(_ screenName: String, screenClass: String? = nil) {
        AdStageManager.shared.trackEvent(
            AdStageEvent.ScreenView(
                screenName: screenName,
                screenClass: screenClass
            )
        )
        print("📺 Screen: \(screenName)")
    }
    
    func trackPurchase(_ order: Order) {
        let items = order.items.map {
            EcommerceItem(
                itemId: $0.product.id,
                itemName: $0.product.name,
                price: $0.product.price,
                quantity: $0.quantity
            )
        }
        
        AdStageManager.shared.trackEvent(
            AdStageEvent.Purchase(
                value: order.totalAmount,
                currency: "KRW",
                transactionId: order.id,
                items: items
            )
        )
        
        print("💰 Purchase: \(order.id)")
    }
    
    func trackError(_ error: Error, context: String) {
        AdStageManager.shared.trackEvent(
            AdStageEvent.Custom(
                params: [
                    "event_type": "error",
                    "error_message": error.localizedDescription,
                    "context": context
                ]
            )
        )
        print("❌ Error: \(context) - \(error)")
    }
}

5. Performance Optimization: Throttling

class ThrottledEventTracker {
    private var lastTrackTimes: [String: TimeInterval] = [:]
    private let throttleInterval: TimeInterval = 2.0  // 2 seconds
    
    func trackEvent(_ event: AdStageEventProtocol) {
        let eventKey = event.eventName
        let now = Date().timeIntervalSince1970
        let lastTime = lastTrackTimes[eventKey] ?? 0
        
        if now - lastTime >= throttleInterval {
            AdStageManager.shared.trackEvent(event)
            lastTrackTimes[eventKey] = now
        } else {
            print("⏱️ Throttled: \(eventKey)")
        }
    }
}
 
// Usage (scroll events, etc.)
let throttledTracker = ThrottledEventTracker()
 
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    throttledTracker.trackEvent(
        AdStageEvent.Custom(
            params: [
                "action": "scroll",
                "offset_y": scrollView.contentOffset.y
            ]
        )
    )
}

Conversion Examples

// 1. Basic event
// OLD: EventTrackingManager.shared.trackEvent(...)
// NEW:
AdStageManager.shared.trackEvent(AdStageEvent.FirstOpen())
 
// 2. Login
// NEW:
AdStageManager.shared.trackEvent(AdStageEvent.Login(method: .email))
 
// 3. Screen view
// NEW:
AdStageManager.shared.trackEvent(AdStageEvent.ScreenView(screenName: "home"))
 
// 4. Custom
// NEW:
AdStageManager.shared.trackEvent(
    AdStageEvent.Custom(params: ["action": "click"])
)

Troubleshooting

1. Compile Error: "currency parameter required"

Problem:

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

Solution:

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

2. Xcode Auto-complete Not Working

Solution:

  1. Clean Build Folder: Product → Clean Build Folder (⇧⌘K)
  2. Delete Derived Data: ~/Library/Developer/Xcode/DerivedData
  3. Reinstall Pods:
pod deintegrate
pod install

3. 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

4. SwiftUI Preview Crash

Problem: AdStageManager initialization error in Preview

Solution:

#if DEBUG
struct ProductDetailView_Previews: PreviewProvider {
    static var previews: some View {
        ProductDetailView(productId: "PROD_123")
            .onAppear {
                // Don't initialize in Preview
                if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == nil {
                    AdStageManager.shared.initialize(
                        apiKey: "test-key",
                        serverUrl: "https://api.adstage.app"
                    )
                }
            }
    }
}
#endif

5. Check Debug Logs

// AppDelegate.swift
func application(...) -> Bool {
    #if DEBUG
    AdStageManager.shared.setDebugMode(true)
    #endif
    
    AdStageManager.shared.initialize(...)
    return true
}

Console Filter:

# Xcode Console
filter: AdStage

Reference

Standards Reference


FAQ

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

Q: Is it compatible with Android SDK?
A: Yes, v3.0 supports the same 46 events as Android SDK with 100% compatibility.

Q: Can I use it with SwiftUI?
A: Yes, fully supported with ObservableObject pattern.


Support

Contact:


© 2025 NBase. All rights reserved.

Table of Contents