Title: Flutter SDK Locale: en URL: https://sensorswave.com/en/docs/data-integration/client-sdks/flutter/ Description: Flutter SDK integration guide and API reference The Sensors Wave Flutter SDK is a mobile-side data collection and AB testing tool designed for Flutter applications. ## Core Features The Flutter SDK provides the following core capabilities: - **Event Tracking**: Manually track custom events and user behaviors - **AutoCapture**: Automatically collect app starts, app ends, page views, page leaves, 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 - **Route Monitoring**: Automatically monitor page route changes and collect page view events - **Batch Sending**: Optimized network request performance, sending up to 10 events in batches every 5 seconds - **Common Properties**: Support for static common properties, automatically attached to all events ## Installation ### Install via pub.dev Add the following to your `pubspec.yaml`: ```yaml dependencies: sensorswave_flutter_sdk: ^0.2.0 ``` Then run: ```bash flutter pub get ``` ## Quick Start ### Basic Initialization Initialize the SDK in your `main.dart`: ```dart void main() { WidgetsFlutterBinding.ensureInitialized(); // Initialize SDK (synchronous method, returns immediately) final sdk = SensorsWaveSDK(); sdk.init('YOUR_SOURCE_TOKEN', config: SensorsConfig.create( apiHost: 'https://your-api-endpoint.com', // Data reporting endpoint debug: false, // Debug mode autoCapture: true // Enable AutoCapture )); runApp(MyApp()); } ``` ### Send Your First Event Once initialized, you can start reporting events immediately: ```dart // Track button click SensorsWaveSDK().trackEvent('ButtonClick', { 'button_name': 'submit', 'page': 'home', }); ``` ### Integrate Route Observer To enable automatic page tracking, add the route observer to your `MaterialApp`: ```dart MaterialApp( navigatorObservers: [ if (SensorsWaveSDK().routeObserver != null) SensorsWaveSDK().routeObserver!, ], // ... other properties ); ``` ## Configuration Options The `config` parameter of the `init` method is a configuration object that supports the following options: | Option | Type | Default | Description | |--------|------|---------|-------------| | `debug` | `bool` | `false` | Whether to enable debug mode, outputs detailed logs to console when enabled | | `apiHost` | `String` | `''` | **Required**, API endpoint for data reporting | | `autoCapture` | `bool` | `true` | Whether to enable AutoCapture, automatically collects app start, end, page views and other events | | `enableClickTrack` | `bool` | `false` | Whether to enable automatic click tracking (tracks main clickable components) | | `enableAB` | `bool` | `false` | Whether to enable A/B testing functionality | | `abRefreshInterval` | `int` | `600000` | A/B test configuration refresh interval (milliseconds), default 10 minutes, minimum 30s | | `batchSend` | `bool` | `true` | Whether to use batch sending, sends up to 10 events in batches every 5 seconds | ### Complete Configuration Example ```dart sdk.init('YOUR_SOURCE_TOKEN', config: SensorsConfig.create( apiHost: 'https://your-api-endpoint.com', debug: true, // Enable debug in development autoCapture: true, // Enable AutoCapture enableClickTrack: true, // Enable click tracking enableAB: true, // Enable A/B testing abRefreshInterval: 10 * 60 * 1000, // Refresh A/B test data every 10 minutes batchSend: true // Batch sending for performance )); ``` > **Tip**: It's recommended to disable `debug` mode in production to avoid excessive console output. ## API Methods ### Event Tracking #### trackEvent - Track Custom Events Manually track custom events and their properties. **Parameters**: - `eventName` (`String`, required): Event name - `properties` (`Map`, optional): Event properties as key-value pairs **Example**: ```dart // Track button click SensorsWaveSDK().trackEvent('ButtonClick', { 'button_name': 'submit', 'page': 'home', }); ``` **Real-world Scenario Examples**: ```dart // E-commerce scenario: User views product SensorsWaveSDK().trackEvent('ProductView', { 'product_id': '12345', 'product_name': 'Wireless Bluetooth Headphones', 'category': 'Electronics', 'price': 299.00, 'currency': 'USD', }); // E-commerce scenario: User adds to cart SensorsWaveSDK().trackEvent('AddToCart', { 'product_id': '12345', 'quantity': 1, 'price': 299.00, }); // Content platform: Article reading SensorsWaveSDK().trackEvent('ArticleRead', { 'article_id': 'article_001', 'title': 'Flutter Performance Optimization Tips', 'category': 'Tech Blog', 'read_duration': 120, // Reading duration (seconds) }); ``` #### track - Advanced Event Tracking Send a complete event object with more fine-grained control. This method allows you to manually specify all event fields. **Parameters**: - `event` (`SensorsSendEvent`, required): Complete event object **Example**: ```dart final event = SensorsSendEvent( event: 'purchaseCompleted', properties: { 'product_id': '12345', 'amount': 99.99, 'currency': 'USD', }, time: DateTime.now().millisecondsSinceEpoch, traceId: 'unique-trace-id-12345', anonId: SensorsWaveSDK().getAnonId(), loginId: SensorsWaveSDK().getLoginId(), userProperties: { 'plan': 'premium', 'signup_date': '2024-01-01', }, ); SensorsWaveSDK().track(event); ``` > **Note**: The `track` method is an advanced feature. In 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 behaviors with the identified user. **Parameters**: - `loginId` (`String | num`, required): Unique identifier for the user (e.g., email, user ID, username) **Example**: ```dart // Set user ID after user login SensorsWaveSDK().identify('user_12345'); ``` **Complete Login Flow Example**: ```dart // User login flow Future handleUserLogin(String email, String password) async { try { // Call login API final response = await http.post( Uri.parse('/api/login'), body: jsonEncode({'email': email, 'password': password}), ); final userId = jsonDecode(response.body)['userId']; // Set user ID and associate anonymous behaviors SensorsWaveSDK().identify(userId); } catch (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 method if you want to identify the user but don't need to associate them. **Parameters**: - `loginId` (`String | num`, required): Unique identifier for the user **Example**: ```dart SensorsWaveSDK().setLoginId('user_12345'); // Also supports numeric type (automatically converted to String) SensorsWaveSDK().setLoginId(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. > **Recommendation**: In most cases, use the `identify` method as it records the user identity association event, which helps with subsequent analysis. #### getLoginId - Get Login User ID Get the currently set login user ID. **Return Value**: `String?` **Example**: ```dart final loginId = SensorsWaveSDK().getLoginId(); if (loginId != null) { print('Current user: $loginId'); } ``` #### getAnonId - Get Anonymous User ID Get the current user's anonymous ID. **Return Value**: `String?` **Example**: ```dart final anonId = SensorsWaveSDK().getAnonId(); print('Anonymous user ID: $anonId'); ``` ### 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. #### profileSet - Set User Properties Set user properties. If properties already exist, they will be overwritten. **Parameters**: - `properties` (`Map`, required): User properties to set **Example**: ```dart // Set user properties after registration await SensorsWaveSDK().profileSet({ 'name': 'John Doe', 'age': 30, 'plan': 'premium', }); ``` #### profileSetOnce - Set Once Only Set user properties only if they don't exist. Existing properties will not be overwritten. **Parameters**: - `properties` (`Map`, required): User properties to set once **Example**: ```dart // Record user's first visit information (recorded only once, will not be overwritten later) await SensorsWaveSDK().profileSetOnce({ 'signup_date': '2024-01-15', 'initial_referrer': 'google', 'initial_campaign': 'spring_sale', }); ``` #### profileIncrement - Increment Numeric Properties Increment or decrement numeric user properties. Only supports numeric properties. **Parameters**: - `properties` (`Map`, required): Properties to increment/decrement and their values **Example**: ```dart // Increment single property await SensorsWaveSDK().profileIncrement({ 'login_count': 1, }); // Increment multiple properties await SensorsWaveSDK().profileIncrement({ '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` (`Map`, required): Properties to append and their array values **Example**: ```dart await SensorsWaveSDK().profileAppend({ '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` (`Map`, required): Properties to append and their array values **Example**: ```dart // First call await SensorsWaveSDK().profileUnion({ 'interests': ['technology', 'gaming'], }); // Second call, 'technology' will not be added again await SensorsWaveSDK().profileUnion({ 'interests': ['technology', 'music'], // Only 'music' will be added }); ``` #### profileUnset - Delete Specific Properties Set specified user properties to null. **Parameters**: - `keys` (`String | List`, required): Property name or array of property names to set to null **Example**: ```dart // Delete single property await SensorsWaveSDK().profileUnset('temporary_campaign'); // Delete multiple properties await SensorsWaveSDK().profileUnset(['old_plan', 'expired_flag', 'temp_id']); ``` #### profileDelete - Delete All User Properties Delete all user properties for the current user. This operation cannot be undone. **Example**: ```dart // Delete all user properties when user closes account await SensorsWaveSDK().profileDelete(); ``` > **Warning**: `profileDelete` will delete all user properties. Use with caution. #### User Property Usage Example **Membership Upgrade Scenario**: ```dart Future handleMembershipUpgrade(String newPlan) async { // Update membership level and upgrade time await SensorsWaveSDK().profileSet({ 'plan': newPlan, 'upgrade_time': DateTime.now().toIso8601String(), }); // Increment upgrade count await SensorsWaveSDK().profileIncrement({ 'upgrade_count': 1, }); // Track upgrade event SensorsWaveSDK().trackEvent('membershipUpgrade', { 'from_plan': 'basic', 'to_plan': newPlan, }); } ``` ### Common Properties Common properties are automatically added to all events, suitable for general information that needs to be included in every event. #### registerCommonProperties - Register Common Properties Register static common properties that will be automatically included in all events. **Parameters**: - `properties` (`Map`, required): Properties to register **Example**: ```dart SensorsWaveSDK().registerCommonProperties({ 'app_version': '1.0.0', 'environment': 'production', 'user_tier': getUserTier(), }); ``` #### clearCommonProperties - Clear Common Properties Remove specified registered common properties. **Parameters**: - `keys` (`List`, required): Array of property names to remove **Example**: ```dart SensorsWaveSDK().clearCommonProperties(['app_version', 'user_session_id']); ``` > **Note**: Common properties increase the data size of each event. It's recommended to only add commonly needed general properties. ### A/B Testing The Flutter SDK has built-in A/B testing support and can retrieve feature gate status and experiment variables. #### Enable A/B Testing ```dart sdk.init('YOUR_SOURCE_TOKEN', config: SensorsConfig.create( apiHost: 'https://your-api-endpoint.com', enableAB: true, // Enable A/B testing abRefreshInterval: 10 * 60 * 1000 // Configuration refresh interval (10 minutes) )); ``` #### checkFeatureGate - Check Feature Gate Check if a feature gate (Feature Flag) is enabled for the current user. **Parameters**: - `key` (`String`, required): Feature gate key **Return Value**: `Future` **Example**: ```dart // Check if feature is enabled final isEnabled = await SensorsWaveSDK().checkFeatureGate('new_checkout_flow'); if (isEnabled) { // Show new feature showNewCheckout(); } else { // Show old feature showOldCheckout(); } ``` #### getExperiment - Get Experiment Variables Get experiment variable data for the current user. **Parameters**: - `key` (`String`, required): Experiment key **Return Value**: `Future>` **Example**: ```dart // Get experiment configuration final experiment = await SensorsWaveSDK().getExperiment('pricing_display'); if (experiment.isNotEmpty) { // Apply experiment configuration final priceFormat = experiment['price_format']; final discountType = experiment['discount_type']; updatePricingDisplay(priceFormat, discountType); } ``` **Complete A/B Testing Example**: ```dart // E-commerce homepage CTA button A/B test Future initHomepageCTA() async { try { final experiment = await SensorsWaveSDK().getExperiment('homepage_cta_test'); if (experiment.isNotEmpty) { final buttonText = experiment['button_text'] ?? 'Buy Now'; final buttonColor = experiment['button_color'] ?? '#ff6600'; final buttonSize = experiment['button_size'] ?? '16px'; // Apply experiment configuration to UI updateCTAButton(buttonText, buttonColor, buttonSize); } } catch (error) { print('Failed to get experiment variables: $error'); // Use default configuration } } ``` > **Tip**: A/B testing features require configuration of experiments and feature gates in the Sensors Wave backend before use. ## AutoCapture When AutoCapture is enabled, the SDK automatically collects the following event types: | Event Name | Description | Trigger Timing | |------------|-------------|----------------| | `$AppInstall` | First install | When app is launched for the first time | | `$AppStart` | App start | When app enters foreground | | `$AppEnd` | App end | When app enters background | | `$AppPageView` | Page view | When user navigates to new page/route | | `$AppPageLeave` | Page leave | When user leaves page/route | | `$AppClick` | Element click | When user clicks an element (requires `enableClickTrack`) | ### Enable AutoCapture ```dart sdk.init('YOUR_SOURCE_TOKEN', config: SensorsConfig.create( apiHost: 'https://your-api-endpoint.com', autoCapture: true, // Enable AutoCapture enableClickTrack: true // Enable automatic click tracking )); ``` ### Click Auto Tracking When `enableClickTrack` is enabled, the SDK automatically tracks clicks on the following Flutter widget types: | Widget Type | Description | |-------------|-------------| | **ElevatedButton** | Material Design elevated button | | **TextButton** | Material Design text button (flat button) | | **OutlinedButton** | Material Design outlined button | | **FilledButton** | Material Design filled button | | **IconButton** | Icon button with an icon | | **ListTile** | Single row in a list with optional leading/trailing components | | **GestureDetector** | Custom gesture detector widget | | **InkWell** | Material InkWell widget | > **Tip**: AutoCapture can significantly reduce manual coding effort, but increases data volume. Enable selectively based on actual needs. ## Important Notes ### Performance Optimization - Avoid calling `trackEvent` frequently in loops; consider merging events or using throttling - Batch sending is enabled by default and effectively reduces network requests - AutoCapture adds some performance overhead; enable only when needed ### Data Security - Do not pass sensitive information in event properties (e.g., passwords, credit card numbers, ID numbers) - Keep Source Token secure and avoid exposing it in public code repositories ### Initialization Timing The SDK's `init` method is **synchronous** and returns immediately. Actual initialization (loading data from storage, collecting device information) happens in the background. You can call other SDK methods immediately after `init()` returns. ```dart void main() { WidgetsFlutterBinding.ensureInitialized(); final sdk = SensorsWaveSDK(); sdk.init('YOUR_SOURCE_TOKEN'); // Synchronous, returns immediately // Can be used immediately sdk.trackEvent('APP_READY'); runApp(MyApp()); } ``` ### FAQ #### What's the difference between `identify()` and `setLoginId()`? **Difference**: - `identify()`: Sets login ID and sends `$Identify` binding event to backend. Use when user logs in. - `setLoginId()`: Only sets login ID locally, no event sent. Use when you need to update ID without triggering binding event. #### When should I disable `autoCapture`? Disable `autoCapture` in the following scenarios: - You want full control over which events to track - You only want to track specific custom events - You need to implement custom page view tracking logic - You want to minimize performance impact #### What's the difference between `batchSend: true` and `batchSend: false`? **Difference**: - `batchSend: true` (default): Events are queued and sent in batches (up to 10 events every 5 seconds). Better performance and network efficiency. - `batchSend: false`: Each event is sent immediately. Better real-time analytics, but uses more network requests. #### How to test SDK during development? 1. Enable debug mode: `sdk.init('your-token', config: SensorsConfig.create(debug: true))` 2. Check console logs for event tracking details 3. Verify events are sent to your analytics dashboard 4. Use a test source token separate from production ## Complete Example The following is a complete example showing how to integrate the SDK into a Flutter application: ```dart void main() { WidgetsFlutterBinding.ensureInitialized(); // Initialize SDK (synchronous, returns immediately) final sdk = SensorsWaveSDK(); sdk.init('your-source-token', config: SensorsConfig.create( debug: false, autoCapture: true, enableAB: true, enableClickTrack: true, batchSend: true, )); runApp(MyApp()); } class MyApp extends StatelessWidget { final sdk = SensorsWaveSDK(); @override Widget build(BuildContext context) { return MaterialApp( title: 'My App', // Add route observer for automatic page tracking navigatorObservers: sdk.routeObserver != null ? [sdk.routeObserver!] : [], home: HomePage(), ); } } class HomePage extends StatelessWidget { final sdk = SensorsWaveSDK(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Home')), body: Column( children: [ ElevatedButton( onPressed: () { // Track custom event sdk.trackEvent('ButtonClick', { 'button_name': 'get_started', 'page': 'home', }); }, child: Text('Get Started'), ), ElevatedButton( onPressed: () async { // Check feature gate final showNewFeature = await sdk.checkFeatureGate('new_dashboard'); if (showNewFeature) { Navigator.push(context, MaterialPageRoute( builder: (_) => NewDashboardPage(), )); } else { Navigator.push(context, MaterialPageRoute( builder: (_) => OldDashboardPage(), )); } }, child: Text('Go to Dashboard'), ), ], ), ); } } class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State { final sdk = SensorsWaveSDK(); void handleLogin(String email, String password) { // Your login logic here // ... // Identify user after successful login sdk.identify(email); } @override Widget build(BuildContext context) { // Your login UI here return Container(); } } ``` ## Related Documentation - [Tracking Strategy](../tracking-strategy.mdx): Learn about the pros and cons of server-side vs client-side tracking - [User Identification Best Practices](../user-identification.mdx): Best practices for user identity identification - [Data Model](../data-model.mdx): Understand Sensors Wave's data structure - [Events and Properties](../events-and-properties.mdx): Event design guidelines and best practices --- **Last Updated**: March 12, 2026 **License**: Apache-2.0