sensorswave_flutter_sdk 0.2.1
sensorswave_flutter_sdk: ^0.2.1 copied to clipboard
Sensors Wave Flutter SDK for event tracking and AB testing.
Sensors Wave Flutter SDK #
Sensors Wave Sensors Wave Flutter SDK is a mobile analytics tracking and AB testing library for Flutter applications. If you're new to Sensor Wave, check out our product and create an account at sensorswave.com.
SDK Usage #
1. Install via pub.dev #
Add the following to your pubspec.yaml:
dependencies:
sensorswave_flutter_sdk: ^0.2.0
Then run:
flutter pub get
2. Initialize the SDK #
import 'package:sensorswave_flutter_sdk/sensorswave_flutter_sdk.dart';
// In your main.dart or app initialization
final sdk = SensorsWaveSDK();
sdk.init('your-source-token', config: SensorsConfig.create(
debug: false,
apiHost: 'https://your-api-host.com',
autoCapture: true,
));
// SDK init is synchronous - you can use it immediately
sdk.trackEvent('APP_READY');
3. Integrate Route Observer #
To enable automatic page tracking, add the route observer to your MaterialApp:
MaterialApp(
navigatorObservers: [
SensorsWaveSDK().routeObserver ?? [],
],
// ... other properties
);
4. Send Custom Events #
SensorsWaveSDK().trackEvent('ButtonClick', {
'button_name': 'submit',
'page': 'home',
});
Configuration Options #
| Option | Type | Default | Description |
|---|---|---|---|
| debug | bool | false | Whether to enable debug mode for logging |
| apiHost | String | '' | API host address for sending events |
| autoCapture | bool | true | Whether to automatically capture app events (app start, app end, page view, page leave) |
| enableClickTrack | bool | false | Whether to enable automatic click tracking on supported widgets |
| enableAB | bool | false | Whether to enable A/B testing feature |
| abRefreshInterval | int | 600000 (10 minutes) | The interval in milliseconds for refreshing A/B test configuration (minimum 30000ms) |
| batchSend | bool | true | Whether to use batch sending mode. When true, events are sent in batches (up to 20 events every 5 seconds). When false, events are sent immediately one by one. |
API Methods #
Event Tracking #
trackEvent
Manually track a custom event with properties.
Parameters:
eventName(String, required): The name of the event to trackproperties(Map<String, dynamic>, optional): Additional properties to include with the event
Example:
SensorsWaveSDK().trackEvent('ButtonClick', {
'button_name': 'submit',
'page': 'home',
'category': 'user_action',
});
track
Track an event with full control over the event structure. This is an advanced method that allows you to specify all event fields manually.
Parameters:
event(SensorsSendEvent, required): Complete event object
Example:
final event = SensorsSendEvent(
event: 'PurchaseCompleted',
properties: {
'product_id': '12345',
'amount': 99.99,
'currency': 'USD',
},
time: DateTime.now().millisecondsSinceEpoch,
traceId: UUID(),
anonId: SensorsWaveSDK().getAnonId(),
loginId: SensorsWaveSDK().getLoginId(),
userProperties: {
'plan': 'premium',
'signup_date': '2024-01-01',
},
);
SensorsWaveSDK().track(event);
User Profile #
profileSet
Set user properties. If a property already exists, it will be overwritten.
Parameters:
properties(Map<String, dynamic>, required): User properties to set
Example:
await SensorsWaveSDK().profileSet({
'name': 'John Doe',
'age': 30,
'plan': 'premium',
});
profileSetOnce
Set user properties only if they don't already exist. Existing properties will not be overwritten.
Parameters:
properties(Map<String, dynamic>, required): User properties to set once
Example:
await SensorsWaveSDK().profileSetOnce({
'signup_date': '2024-01-15',
'initial_referrer': 'google',
'initial_campaign': 'spring_sale',
});
profileIncrement
Increment numeric user properties by a specified amount. Only supports numeric properties.
Parameters:
properties(Map<String, num>, required): Properties to increment with numeric values
Example:
// 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 new values to list-type user properties without deduplication.
Parameters:
properties(Map<String, dynamic>, required): Properties with list values to append
Example:
await SensorsWaveSDK().profileAppend({
'categories_viewed': ['electronics', 'mobile_phones'],
'tags': ['new_customer', 'q1_2024'],
});
profileUnion
Append new values to list-type user properties with deduplication (avoids duplicate values).
Parameters:
properties(Map<String, List>, required): Properties with list values to append with deduplication
Example:
await SensorsWaveSDK().profileUnion({
'interests': ['technology', 'gaming'],
'newsletter_subscriptions': ['tech_news'],
});
profileUnset
Set specific user properties to null (effectively removing them).
Parameters:
keys(String or List
Example:
// Unset single property
await SensorsWaveSDK().profileUnset('temporary_campaign');
// Unset multiple properties
await SensorsWaveSDK().profileUnset(['old_plan', 'expired_flag', 'temp_id']);
profileDelete
Delete all user profile data for the current user. This operation cannot be undone.
Example:
await SensorsWaveSDK().profileDelete();
User Identification #
identify
Set the login ID for the current user and send a $Identify binding event to the backend.
Parameters:
loginId(String or num, required): Unique identifier for the user (e.g., email, user ID, username)
Example:
SensorsWaveSDK().identify('user_12345');
setLoginId
Set the login ID for the current user without sending a binding event.
Difference from identify:
identify: Sets login ID AND sends a$Identifyevent to backendsetLoginId: Only sets login ID locally, no event sent
Parameters:
loginId(String or num, required): Unique identifier for the user
Example:
// Set login ID without triggering event
SensorsWaveSDK().setLoginId('user_12345');
// Also supports numeric types (auto-converted to String)
SensorsWaveSDK().setLoginId(12345);
getLoginId
Get the current login ID.
Returns: String?
Example:
final loginId = SensorsWaveSDK().getLoginId();
getAnonId
Get the anonymous ID for the current user.
Returns: String?
Example:
final anonId = SensorsWaveSDK().getAnonId();
Common Properties #
registerCommonProperties
Register static common properties that will be included with all events. This is useful for including global context like app version, environment, or user-specific data.
Parameters:
properties(Map<String, dynamic>, required): Properties to register
Example:
SensorsWaveSDK().registerCommonProperties({
'app_version': '1.0.0',
'environment': 'production',
'user_tier': getUserTier(),
});
clearCommonProperties
Remove specific registered common properties.
Parameters:
keys(List
Example:
SensorsWaveSDK().clearCommonProperties(['app_version', 'user_session_id']);
A/B Testing #
checkFeatureGate
Check if a feature gate (feature flag) is enabled for the current user.
Parameters:
key(String, required): The feature gate key to check
Returns: Future
Example:
// Check if a 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 variant data for the current user.
Parameters:
key(String, required): The experiment key to retrieve
Returns: Future<Map<String, dynamic>>
Example:
// Get experiment configuration
final experiment = await SensorsWaveSDK().getExperiment('homepage_layout');
if (experiment.isNotEmpty) {
// Apply experiment configuration
applyLayout(experiment['layout_type']);
}
Other Methods #
destroy
Clean up and release all SDK resources. Call this when the app is terminating.
Example:
await SensorsWaveSDK().destroy();
Best Practices #
1. Initialization Timing #
Initialize the SDK as early as possible in your app's lifecycle:
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Initialize SDK
final sdk = SensorsWaveSDK();
sdk.init('your-source-token');
runApp(MyApp());
}
2. User Identity Management #
Use identify() when a user logs in to track their identity across sessions:
// When user logs in
sdk.identify('user_12345');
// When you need to update login ID without sending event
sdk.setLoginId('new.user_12345');
3. Event Naming Convention #
- Use descriptive event names:
ButtonClick,PurchaseCompleted - Avoid using
$prefix for custom events (it's reserved for preset events)
4. Property Design #
- Use snake case for property keys:
user_id,product_name,is_premium - Include context in properties:
{ 'button_name': 'submit', 'page': 'checkout' } - Use consistent data types for the same property across events
5. Common Properties #
Register app-level properties once instead of including them in every event:
// Set once at app startup
sdk.registerCommonProperties({
'app_version': '1.0.0',
'user_tier': getUserTier(),
'environment': 'production',
});
// These will be automatically included in all events
sdk.trackEvent('any_event'); // Properties above are included
6. Error Handling #
The SDK handles errors internally and logs them when debug mode is enabled:
sdk.init('your-source-token', config: SensorsConfig.create(
debug: true, // Enable debug logs during development
));
7. Memory Management #
The SDK manages resources automatically. Call destroy() only when:
- User logs out and you want to clear all data
- App is shutting down permanently
- You need to reinitialize the SDK with different configuration
await sdk.destroy();
FAQ #
Q: What's the difference between identify() and setLoginId()? #
A:
identify(): Sets the login ID AND sends a$Identifybinding event to the backend. Use this when a user logs in.setLoginId(): Only sets the login ID locally without sending an event. Use this when you need to update the ID but don't want to trigger the binding event.
Q: Is init() synchronous or asynchronous? #
A: The init() method is synchronous and returns immediately. Actual initialization (loading data from storage, collecting device info, initializing plugins) happens in the background. You can call other SDK methods right after init() returns.
Q: When should I disable autoCapture? #
A: Disable autoCapture if:
- You want full control over what events are tracked
- You only want to track specific custom events
- You need to implement custom page view tracking logic
- You want to minimize performance impact
Q: What's the difference between batchSend: true and batchSend: false? #
A:
batchSend: true(default): Events are queued and sent in batches (up to 20 events every 5 seconds). Better for performance and network efficiency.batchSend: false: Each event is sent immediately. Better for real-time analytics but uses more network requests.
Q: How do I track events that need to be sent immediately? #
A: The SDK automatically handles critical events (like $AppEnd) with immediate sending. For custom events, use batchSend: false or call flush() after tracking.
Q: Can I use the SDK in the background? #
A: Yes, but note that some features like automatic page tracking won't work in the background since there are no route changes. Event tracking and user profile methods work normally.
Q: How do I test the SDK during development? #
A:
- Enable debug mode:
sdk.init('your-token', config: SensorsConfig.create(debug: true)) - Check console logs for event tracking details
- Verify events are sent to your analytics dashboard
- Use a test source token separate from production
Q: What happens if I call init() multiple times? #
A: The SDK ignores subsequent init() calls after the first initialization. The first call's configuration is used throughout the SDK lifecycle.
Q: How do I clear user data? #
A: Use the appropriate method based on your needs:
- Clear user properties:
sdk.profileDelete() - Clear login ID:
sdk.setLoginId(null)orsdk.setLoginId('') - Clear all data:
await sdk.destroy()then reinitialize
Q: Does the SDK work offline? #
A: Yes! Events are queued in local storage using SharedPreferences. When the device comes back online, queued events are automatically sent.
Supported Event Types #
The SDK automatically captures the following event types when autoCapture is enabled:
- $AppInstall: Triggered on first app launch
- $AppStart: Triggered when the app enters the foreground
- $AppEnd: Triggered when the app enters the background
- $AppPageView: Triggered when a user navigates to a new page/route
- $AppPageLeave: Triggered when a user leaves a page/route
- $AppClick: Triggered on element interactions (only when
enableClickTrackis true)
AppClick - Supported Elements #
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 widgets |
| GestureDetector | Custom gesture detector widget |
| InkWell | Material ink splash widget (also covers widgets that use InkWell internally) |
How It Works
- Enable click tracking in the SDK config:
sdk.init('your-source-token', config: SensorsConfig.create(
enableClickTrack: true,
));
- Use any of the supported widgets normally - no wrapper components needed:
// These will be tracked automatically
ElevatedButton(
onPressed: () => doSomething(),
child: Text('Click Me'),
)
TextButton(
onPressed: () => doSomething(),
child: Text('Text Button'),
)
IconButton(
icon: Icon(Icons.favorite),
onPressed: () => doSomething(),
)
ListTile(
title: Text('Title'),
onTap: () => doSomething(),
)
Event Properties
Each $AppClick event includes the following properties:
| Property | Description |
|---|---|
$element_type |
Type of the clicked element (e.g., "ElevatedButton", "TextButton") |
$element_content |
Text content of the clicked element (if available) |
$screen_name |
Current screen/page name when the click occurred |
$event_duration |
Time in seconds since the page was viewed |
$element_selector |
CSS-style selector for the element (e.g., "[ElevatedButton]") |
$element_path |
Full path to the element (e.g., "/HomePage/ElevatedButton") |
Manual Click Tracking
Custom events can be tracked using the trackEvent() or track() methods.
Complete Example #
Here's a complete example showing how to integrate the SDK into a Flutter app:
import 'package:flutter/material.dart';
import 'package:sensorswave_flutter_sdk/sensorswave_flutter_sdk.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<LoginPage> {
final sdk = SensorsWaveSDK();
void handleLogin(String email, String password) {
// Your login logic here
// ...
// After successful login, identify the user
sdk.identify(email);
}
@override
Widget build(BuildContext context) {
// Your login UI here
return Container();
}
}
class ProductPage extends StatelessWidget {
final sdk = SensorsWaveSDK();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Product')),
body: ListView(
children: [
ElevatedButton(
onPressed: () {
// Increment purchase count
sdk.profileIncrement({'purchase_count': 1});
// Track purchase event
sdk.trackEvent('product_purchase', {
'product_id': '12345',
'product_name': 'Premium Plan',
'price': 99.99,
});
},
child: Text('Buy Now'),
),
],
),
);
}
}
class SettingsPage extends StatefulWidget {
@override
_SettingsPageState createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
final sdk = SensorsWaveSDK();
void handleLogout() {
// Track logout event
sdk.trackEvent('UserLogout');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Settings')),
body: ListView(
children: [
ListTile(
title: Text('Logout'),
onTap: handleLogout,
),
],
),
);
}
}
License #
Apache-2.0