Flutter SDK
Official Flutter SDK for iOS, Android, and web. Auto-tracks screen views, app lifecycle events, and supports batched event delivery.
Installation
Add to your pubspec.yaml:
dependencies: retenshun: ^1.0.0
Then run:
flutter pub get
Initialization
Initialize once in your main() function before runApp():
import 'package:retenshun/retenshun.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Retenshun.init(
projectId: 'YOUR_PROJECT_ID',
apiKey: 'pk_live_YOUR_PUBLIC_KEY',
// Optional
apiUrl: 'https://your-domain.com/api/v1',
debug: true, // Console logging
autoTrackScreens: true, // Track screen views via NavigatorObserver
autoTrackLifecycle: true, // Track app_opened / app_backgrounded
flushAt: 20, // Batch size before auto-flush
flushIntervalSeconds: 30, // Periodic flush interval
);
runApp(const MyApp());
}Auto Screen Tracking
Add RetenshunObserver to your app for automatic screen tracking:
MaterialApp( navigatorObservers: [RetenshunObserver()], // ... )
This tracks screen views automatically when routes are pushed, popped, or replaced. Uses RouteSettings.name by default.
Custom Screen Name Extractor
RetenshunObserver(
screenNameExtractor: (route) {
// Custom logic to extract screen name
return route?.settings.name?.replaceAll('/', ' ').trim();
},
)Identify Users
Call on login or registration. The user ID persists across app restarts via SharedPreferences.
// On login success
Retenshun.identify('user_123', properties: {
'email': 'john@example.com',
'name': 'John Doe',
'plan': 'pro',
'createdAt': '2026-01-15',
});Track Events
// Basic event
Retenshun.track('button_clicked', properties: {
'button': 'signup_cta',
'screen': 'home',
});
// Feature usage
Retenshun.track('feature_used', properties: {
'feature': 'csv_export',
});
// Purchase
Retenshun.track('purchase', properties: {
'amount': 49.99,
'currency': 'USD',
'product_id': 'prod_1',
});Manual Screen Tracking
If you prefer manual tracking over the NavigatorObserver:
Retenshun.screen('Product Detail', properties: {
'product_id': 'prod_1',
'category': 'Electronics',
});Update User Properties
Retenshun.setUserProperties({
'plan': 'enterprise',
'company': 'Acme Inc',
'teamSize': 25,
});E-commerce Tracking
Built-in helpers with standardized event names:
// Product viewed
Retenshun.ecommerce.productViewed(
productId: 'prod_1',
name: 'Wireless Headphones',
price: 79.99,
category: 'Electronics',
);
// Added to cart
Retenshun.ecommerce.addedToCart(
productId: 'prod_1',
name: 'Wireless Headphones',
price: 79.99,
quantity: 1,
);
// Removed from cart
Retenshun.ecommerce.removedFromCart(productId: 'prod_1');
// Checkout started
Retenshun.ecommerce.checkoutStarted(
cartId: 'cart_abc',
total: 159.98,
itemCount: 2,
);
// Order completed
Retenshun.ecommerce.orderCompleted(
orderId: 'ord_123',
total: 159.98,
currency: 'USD',
products: [
{'product_id': 'prod_1', 'quantity': 2, 'price': 79.99},
],
);Logout / Reset
// On logout Retenshun.reset();
Clears the user identity, generates a new anonymous ID, and flushes pending events.
Event Batching
Events are queued and sent in batches for performance. The SDK flushes automatically when:
- The queue reaches
flushAtevents (default: 20) - Every
flushIntervalSecondsseconds (default: 30) - The app goes to background
You can also flush manually:
await Retenshun.flush();
RetenshunProvider Widget
Optional widget for accessing the SDK via BuildContext:
// Wrap your app RetenshunProvider( child: MaterialApp(...), ) // Access from widget tree final retenshun = RetenshunProvider.of(context);
Note: The provider is optional. You can use Retenshun.* static methods directly anywhere in your app.
Utility Methods
// Get current user ID (null if not identified) String? userId = Retenshun.getUserId(); // Get anonymous ID (always set) String anonId = Retenshun.getAnonymousId(); // Clean up (typically not needed) Retenshun.dispose();
Complete Example
import 'package:flutter/material.dart';
import 'package:retenshun/retenshun.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Retenshun.init(
projectId: 'proj_abc123',
apiKey: 'pk_live_your_key',
debug: true,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return RetenshunProvider(
child: MaterialApp(
navigatorObservers: [RetenshunObserver()],
home: const HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Retenshun.identify('user_123', properties: {
'email': 'john@example.com',
});
},
child: const Text('Login'),
),
ElevatedButton(
onPressed: () {
Retenshun.track('button_clicked');
},
child: const Text('Track Event'),
),
ElevatedButton(
onPressed: () => Retenshun.reset(),
child: const Text('Logout'),
),
],
),
),
);
}
}