Title: iOS SDK Locale: en URL: https://sensorswave.com/en/docs/data-integration/client-sdks/ios/ Description: iOS SDK integration guide and API reference The Sensors Wave iOS SDK is a client-side data collection and A/B testing tool designed for iOS applications. ## Core Features The iOS SDK provides the following core capabilities: - **Event Tracking**: Manually track custom events and user behaviors - **AutoCapture**: Automatically collect app start, page views, clicks, and other events - **User Identification**: Support for Anonymous ID and Login ID identity association - **User Property Management**: Full User Property operations (set, append, increment, etc.) - **A/B Testing Integration**: Support for Feature Gate and experiment variable retrieval - **Batch Sending**: Optimized network request performance with batch event sending - **Common Properties**: Support for static common properties, automatically attached to all events - **Thread Safety**: All operations are guaranteed to be thread-safe ## Installation ### CocoaPods Integration (Recommended) Add to your `Podfile`: ```ruby pod 'SensorswaveSDK' ``` Then run in the terminal: ```bash pod install ``` ### Manual Integration 1. Get the SDK binary from [GitHub](https://github.com/sensorswave/ios-sdk) 2. Drag the `SensorswaveSDK.xcframework` bundle into your Xcode project 3. Make sure to check "Copy items if needed" 4. Add the following frameworks to your project settings: - `Foundation.framework` - `UIKit.framework` - `CoreTelephony.framework` ## Quick Start ### Basic Initialization Initialize the SDK in the `application(_:didFinishLaunchingWithOptions:)` method of `AppDelegate.swift`: ```swift @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Create configuration let config = SensorswaveConfig() config.debug = false config.apiHost = "https://your-api-host.com" config.autoCapture = true // Initialize the SDK Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) return true } } ``` ### Send Your First Event After initialization, you can start tracking events immediately: ```swift // Track a button click Sensorswave.getInstance().trackEvent(eventName: "ButtonClick", properties: [ "button_name": "submit", "page": "home" ]) ``` ## Configuration Options `SensorswaveConfig` supports the following configuration options: | Option | Type | Default | Description | |--------|------|--------|------| | `debug` | `Bool` | `false` | Whether to enable debug mode; outputs detailed logs to the console when enabled | | `apiHost` | `String` | `''` | **Required**. API endpoint for data reporting | | `autoCapture` | `Bool` | `true` | Whether to enable AutoCapture for app start, page views, and other events | | `enableClickTrack` | `Bool` | `false` | Whether to enable automatic click tracking | | `batchSend` | `Bool` | `false` | Whether to use batch sending; sends after collecting 20 events or every 5 seconds | | `enableAB` | `Bool` | `false` | Whether to enable A/B testing | | `abRefreshInterval` | `TimeInterval` | `600000` | A/B testing configuration refresh interval (milliseconds), default 10 minutes, minimum 30 seconds | ### Complete Configuration Example ```swift let config = SensorswaveConfig() config.debug = true // Enable debug in development config.apiHost = "https://your-api-host.com" config.autoCapture = true // Enable AutoCapture config.enableClickTrack = true // Enable click tracking config.batchSend = true // Batch sending for performance config.enableAB = true // Enable A/B testing config.abRefreshInterval = 10 * 60 * 1000 // Refresh A/B test data every 10 minutes Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) ``` > **Tip**: In production, it is recommended to disable `debug` mode to avoid excessive logging in the console. ## API Methods ### Event Tracking #### trackEvent - Track Custom Events Manually track custom events and their properties. **Parameters**: - `eventName` (String, required): Event name - `properties` (Dictionary, optional): Event properties as key-value pairs **Example**: ```swift // Track a button click Sensorswave.getInstance().trackEvent(eventName: "ButtonClick", properties: [ "button_name": "submit", "page": "home" ]) ``` **Real-world examples**: ```swift // E-commerce: user views a product Sensorswave.getInstance().trackEvent(eventName: "ProductView", properties: [ "product_id": "12345", "product_name": "Wireless Bluetooth Headphones", "category": "Electronics", "price": 299.00, "currency": "CNY" ]) // E-commerce: user adds to cart Sensorswave.getInstance().trackEvent(eventName: "AddToCart", properties: [ "product_id": "12345", "quantity": 1, "price": 299.00 ]) // Content: article read Sensorswave.getInstance().trackEvent(eventName: "article_read", properties: [ "article_id": "article_001", "title": "Swift Performance Optimization Tips", "category": "Tech Blog", "read_duration": 120 // Reading duration (seconds) ]) ``` #### track - Advanced Event Tracking Send a fully-populated event object for more granular control. This method allows you to manually specify all event fields. **Parameters**: - `event` (AdvanceEvent, required): Full event object containing the following fields: - `event` (String, required): Event name - `properties` (Dictionary, optional): Event properties - `time` (Int64, required): Timestamp (milliseconds) - `anon_id` (String, optional): Anonymous user ID - `login_id` (String, optional): Logged-in user ID. At least one of login_id or anon_id must be provided; when both are provided, login_id takes priority - `trace_id` (String, required): Request Trace ID - `user_properties` (Dictionary, optional): User properties **Example**: ```swift Sensorswave.getInstance().track(event: [ "event": "purchase_completed", "properties": [ "product_id": "12345", "amount": 99.99, "currency": "USD" ], "time": Int64(Date().timeIntervalSince1970 * 1000), "trace_id": UUID().uuidString, "login_id": "user_12345", "user_properties": [ "plan": "premium", "signup_date": "2024-01-01" ] ]) ``` > **Note**: The `track` method is an advanced feature. For most scenarios, `trackEvent` is sufficient. ### User Identification #### identify - Set Login User ID Set the Login user ID and send a binding event to associate anonymous behavior with the identified user. **Parameters**: - `loginId` (String, required): User's unique identifier (e.g., email, user ID, username) **Example**: ```swift // Set user ID after login Sensorswave.getInstance().identify(loginId: "user_12345") ``` **Complete login flow example**: ```swift // User login flow func handleUserLogin(email: String, password: String) { // Call login API loginUser(email: email, password: password) { result in switch result { case .success(let userId): // Set user ID and associate anonymous behavior Sensorswave.getInstance().identify(loginId: userId) // Track login event Sensorswave.getInstance().trackEvent(eventName: "user_login", properties: [ "login_method": "email" ]) case .failure(let error): print("Login failed: \(error)") } } } ``` > **Important**: If the `loginId` contains sensitive information (such as phone numbers, email addresses, ID numbers, etc.), please encrypt it before transmission to avoid sending sensitive data in plain text. #### setLoginId - Set Login ID Only Set the Login user ID without sending a binding event. Use this if you only want to identify the user without associating their identity. **Parameters**: - `loginId` (String, required): User's unique identifier **Example**: ```swift Sensorswave.getInstance().setLoginId(loginId: "user_12345") ``` > **Important**: If the `loginId` contains sensitive information (such as phone numbers, email addresses, ID numbers, etc.), please encrypt it before transmission to avoid sending sensitive data in plain text. > **Usage recommendation**: In most cases, the `identify` method is recommended because it records the user identity association event, which aids in subsequent analysis. ### User Properties User Properties describe user characteristics such as membership level, registration time, preferences, etc. Unlike Event Properties, User Properties are persistently stored and associated with the user. #### setProfile - Set User Properties Set User Properties, overwriting if they already exist. **Parameters**: - `properties` (Dictionary, required): User properties to set **Example**: ```swift // Set User Properties after registration Sensorswave.getInstance().setProfile(properties: [ "name": "John", "age": 30, "plan": "premium" ]) ``` #### setOnceProfile - Set Only Once Set User Properties only if they don't already exist; existing properties will not be overwritten. **Parameters**: - `properties` (Dictionary, required): User properties to set **Example**: ```swift // Record first visit info (recorded once, never overwritten) Sensorswave.getInstance().setOnceProfile(properties: [ "signup_date": "2024-01-15", "initial_referrer": "google", "initial_campaign": "spring_sale" ]) ``` #### profileIncrement - Increment Numeric Properties Perform increment operations on numeric User Properties. Only supports numeric properties. **Parameters**: - `properties` (Dictionary, required): Properties and their increment values **Example**: ```swift // Increment a single property Sensorswave.getInstance().profileIncrement(properties: [ "login_count": 1 ]) // Increment multiple properties Sensorswave.getInstance().profileIncrement(properties: [ "login_count": 1, "points_earned": 100, "purchases_count": 1 ]) ``` #### profileAppend - Append to Array Properties Append new values to array-type User Properties without deduplication. **Parameters**: - `properties` (Dictionary, required): Properties and their array values to append **Example**: ```swift Sensorswave.getInstance().profileAppend(properties: [ "categories_viewed": ["electronics", "mobile_phones"], "tags": ["new_customer", "q1_2024"] ]) ``` #### profileUnion - Append to Set Properties (Deduplicated) Append new values to array-type User Properties with automatic deduplication. **Parameters**: - `properties` (Dictionary, required): Properties and their array values to append **Example**: ```swift // First call Sensorswave.getInstance().profileUnion(properties: [ "interests": ["technology", "gaming"] ]) // Second call, 'technology' will not be added again Sensorswave.getInstance().profileUnion(properties: [ "interests": ["technology", "music"] // Only 'music' will be added ]) ``` #### profileUnset - Delete Specified Properties Set specified User Properties to null. **Parameters**: - `key` (String, optional): Single property name to set to null - `keys` ([String], optional): Array of property names to set to null **Example**: ```swift // Unset a single property Sensorswave.getInstance().profileUnset(key: "temporary_campaign") // Unset multiple properties Sensorswave.getInstance().profileUnset(keys: ["old_plan", "expired_flag", "temp_id"]) ``` #### profileDelete - Delete All User Properties Delete all User Property data for the current user. This operation is irreversible. **Example**: ```swift // Delete all User Properties when the user deactivates their account Sensorswave.getInstance().profileDelete() ``` > **Warning**: `profileDelete` deletes all User Properties. Use with caution. #### User Property Usage Example **Membership upgrade scenario**: ```swift func handleMembershipUpgrade(newPlan: String) { // Update membership level and upgrade time Sensorswave.getInstance().setProfile(properties: [ "plan": newPlan, "upgrade_time": ISO8601DateFormatter().string(from: Date()) ]) // Increment upgrade count Sensorswave.getInstance().profileIncrement(properties: [ "upgrade_count": 1 ]) // Track upgrade event Sensorswave.getInstance().trackEvent(eventName: "membership_upgrade", properties: [ "from_plan": "basic", "to_plan": newPlan ]) } ``` ### Common Properties Common properties are automatically added to all events, suitable for universal information that should be included in every event. The iOS SDK currently supports static common properties. #### registerCommonProperties - Register Common Properties Register static common properties that will be automatically included in all events. **Parameters**: - `properties` (Dictionary, required): Properties to register **Example**: ```swift Sensorswave.getInstance().registerCommonProperties(properties: [ // Static properties "app_version": "1.0.0", "environment": "production", "user_role": "guest" ]) ``` #### clearCommonProperties - Clear Common Properties Remove specified registered common properties. **Parameters**: - `keys` ([String], required): Array of property names to remove **Example**: ```swift Sensorswave.getInstance().clearCommonProperties(keys: ["app_version", "user_role"]) ``` > **Note**: The iOS SDK currently only supports static properties. Common properties increase the data size of every event. Only add truly necessary universal properties. ### A/B Testing The iOS SDK has built-in A/B testing support for retrieving Feature Gate states and experiment variables. #### Enable A/B Testing ```swift config.enableAB = true config.abRefreshInterval = 10 * 60 * 1000 // Configuration refresh interval (10 minutes) ``` #### checkFeatureGate - Check Feature Gate Check whether a Feature Gate is enabled for the current user. Returns the result via a callback function. **Parameters**: - `key` (String, required): Key of the Feature Gate - `callback` (Bool -> Void, required): Callback function returning the Feature Gate state **Example**: ```swift // Check if a feature is enabled Sensorswave.getInstance().checkFeatureGate(key: "new_checkout_flow") { isEnabled in DispatchQueue.main.async { if isEnabled { // Show new feature self.showNewCheckout() } else { // Show old feature self.showOldCheckout() } } } ``` #### getExperiment - Get Experiment Variables Get the current user's experiment variable data. Returns the experiment configuration object via a callback function. **Parameters**: - `key` (String, required): Key of the Experiment - `callback` ([String: Any]? -> Void, required): Callback function returning the experiment configuration **Example**: ```swift // Get experiment configuration Sensorswave.getInstance().getExperiment(key: "pricing_display") { config in DispatchQueue.main.async { guard let config = config else { // Use default configuration self.applyDefaultPricing() return } // Apply experiment configuration if let priceFormat = config["price_format"] as? String, let discountType = config["discount_type"] as? String { self.updatePricingDisplay(format: priceFormat, discount: discountType) } } } ``` **Complete A/B testing example**: ```swift // E-commerce homepage CTA button A/B test func initHomepageCTA() { Sensorswave.getInstance().getExperiment(key: "homepage_cta_test") { config in DispatchQueue.main.async { guard let config = config else { // Use default configuration self.applyDefaultCTA() return } // Apply experiment configuration let buttonText = (config["button_text"] as? String) ?? "Buy Now" let buttonColor = (config["button_color"] as? String) ?? "#ff6600" let buttonSize = (config["button_size"] as? String) ?? "16" self.updateCTAButton( text: buttonText, color: UIColor(hex: buttonColor), fontSize: CGFloat(Float(buttonSize) ?? 16) ) } } } // Initialize on page load override func viewDidLoad() { super.viewDidLoad() initHomepageCTA() } ``` > **Tip**: A/B testing features require configuring experiments and Feature Gates in the SensorsWave dashboard before use. ## AutoCapture When AutoCapture is enabled, the SDK automatically collects the following event types: | Event Name | Description | Trigger Timing | |---------|------|---------| | `$AppStart` | App start | When the app starts | | `$AppEnd` | App end | When the app ends | | `$AppInstall` | First app install | On first app installation (once only) | | `$AppPageView` | Page view | When a user visits a page | | `$AppPageLeave` | Page leave | When a user leaves a page | | `$AppClick` | Element click | When a user clicks an element (requires `enableClickTrack`) | ### Enable AutoCapture ```swift let config = SensorswaveConfig() config.autoCapture = true // Enable AutoCapture config.enableClickTrack = true // Enable automatic click tracking Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) ``` ### Tracking Page Views The SDK automatically tracks page views (when `autoCapture = true`). The SDK automatically sends `$AppPageView` events. > **Tip**: AutoCapture can significantly reduce manual coding effort but increases data volume. Enable selectively based on actual needs. ## Batch Sending Enabling batch sending reduces network request frequency and improves performance: ```swift config.batchSend = true ``` **Batch sending behavior**: - Sends immediately after collecting 10 events - Or sends on a 5-second timer - Uses a thread-safe queue for management **Advantages**: - Reduces network request frequency - Saves battery consumption - Improves sending efficiency ## Important Notes ### Performance Optimization - Batch sending is not enabled by default; it is recommended to enable it in production for performance optimization - AutoCapture adds some performance overhead; enable only when needed - Disable debug mode to reduce log output ### Data Security - Do not pass sensitive information in event properties (e.g., passwords, credit card numbers, ID numbers) - Keep the Source Token secure; avoid exposing it in public code repositories - All data is transmitted via HTTPS encryption ### Thread Safety All operations in the SDK are thread-safe: - **PersistentQueue** - Uses `NSLock` to protect all queue operations - **Network requests** - Supports multi-threaded concurrency - **User Properties** - Uses synchronization mechanisms to ensure data consistency ### Error Handling and Retry The SDK has built-in intelligent error handling and retry mechanisms: 1. **Persistent queue** - Failed requests are saved locally 2. **Exponential backoff retry** - Uses exponential backoff algorithm 3. **App restart recovery** - Automatically sends previously failed requests after app restart ## FAQ ### Why isn't my data being reported successfully? Check the following: 1. **Is the Source Token correct**: Confirm the `sourceToken` parameter is correct 2. **Is the reporting endpoint correct**: Confirm the `apiHost` configuration is correct 3. **Network connection**: Confirm the device has a normal network connection 4. **Debug mode**: Enable `debug = true` to check console logs ### How do I enable debug mode? ```swift let config = SensorswaveConfig() config.debug = true ``` When enabled, detailed log information is output to the console for debugging. ### How do I track user behavior? ```swift // User login Sensorswave.getInstance().identify(loginId: "user123") // Track purchase behavior Sensorswave.getInstance().trackEvent(eventName: "Purchase", properties: [ "product_id": "12345", "amount": 99.99 ]) // Set User Properties Sensorswave.getInstance().setProfile(properties: [ "total_spent": 999.99, "purchase_count": 15 ]) ``` ### How is network failure handled? The SDK automatically handles network failures: - Failed requests are saved to a local queue - Automatically retried after app restart - Uses exponential backoff strategy to avoid server pressure ### How do I use A/B testing? ```swift // 1. Enable A/B testing config.enableAB = true // 2. Check Feature Gate Sensorswave.getInstance().checkFeatureGate(key: "new_feature") { isEnabled in DispatchQueue.main.async { if isEnabled { self.enableNewFeature() } } } // 3. Get experiment configuration Sensorswave.getInstance().getExperiment(key: "pricing_display") { config in DispatchQueue.main.async { if let config = config, let price = config["price"] as? Double { self.updatePrice(price) } } } ``` ## Best Practices ### Initialization Timing Initialize the SDK as early as possible in `application(_:didFinishLaunchingWithOptions:)`: ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Initialize the SDK as early as possible let config = SensorswaveConfig() config.debug = false config.apiHost = "https://api.example.com" config.batchSend = true Sensorswave.getInstance().setup( sourceToken: "your-source-token", config: config ) return true } ``` ### Event Property Guidelines **Recommended practices**: ```swift // Recommended: use meaningful property names Sensorswave.getInstance().trackEvent(eventName: "ProductView", properties: [ "product_id": "12345", "product_name": "iPhone 15 Pro", "category": "electronics", "price": 999.99, "in_stock": true ]) ``` **Practices to avoid**: ```swift // Not recommended: unclear property names Sensorswave.getInstance().trackEvent(eventName: "event", properties: [ "data": "some data", "info": "test" ]) ``` **Property naming conventions**: - Use snake_case: `button_name` rather than `buttonName` - Use meaningful names: `product_id` rather than `id` - Avoid using system reserved words (properties starting with `$`) ### Production Configuration ```swift let config = SensorswaveConfig() config.debug = false // Disable debug config.batchSend = true // Enable batch sending config.autoCapture = true // Enable AutoCapture ``` ## Related Documentation - [Tracking Strategy](../tracking-strategy.mdx): Understand the pros and cons of server-side and client-side tracking - [How to Properly Identify Users](../user-identification.mdx): Best practices for user identity recognition - [Data Model](../data-model.mdx): Understand the SensorsWave data structure - [Events and Properties](../events-and-properties.mdx): Event design guidelines and best practices --- **Last updated**: February 27, 2026 **License**: Apache-2.0