Rybbit Flutter SDK
⚠️ Note: This is an unofficial, community-maintained Flutter SDK for Rybbit Analytics. While functional, this package may have incomplete features or limitations compared to the official web SDK. Use at your own discretion.
A Flutter client SDK for Rybbit Analytics - a modern, open-source web & product analytics platform. Track events, pageviews, and user interactions in your Flutter applications across mobile, web, and desktop.
Features
✨ Comprehensive Analytics Tracking
- 📊 Pageview tracking with automatic screen navigation detection
- 🎯 Custom event tracking with arbitrary properties
- 🔗 Outbound link tracking (external URLs, deep links, app store links)
- ❌ Error tracking with stack traces and context
- 👤 User identification with traits (custom user properties)
- 📱 App lifecycle tracking (foreground/background)
- 📦 Offline event queueing — events are persisted locally and sent automatically when connectivity is restored
Installation
Add rybbit_flutter to your pubspec.yaml:
dependencies:
rybbit_flutter: ^0.6.0
Run:
flutter pub get
Quick Start
1. Get Your Credentials
- Sign up at Rybbit Analytics
- Create a new site/project
- Copy your Site ID and generate an API Key
2. Initialize the SDK
import 'package:rybbit_flutter/rybbit_flutter.dart';
// Initialize in your main() function or app startup
await RybbitFlutter.instance.initialize(
RybbitConfig(
apiKey: 'rb_your_api_key_here',
siteId: 'your_site_id',
enableLogging: true, // Enable for development
),
);
3. Add Route Observer (Optional)
For automatic screen tracking, add the route observer to your MaterialApp:
MaterialApp(
navigatorObservers: [
RybbitFlutter.instance.routeObserver,
],
// ... rest of your app
)
4. Start Tracking
// Track a pageview manually
await RybbitFlutter.instance.trackPageView(
pathname: '/home',
pageTitle: 'Home Screen',
queryParams: {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'spring_sale',
},
);
// Track custom events
await RybbitFlutter.instance.trackEvent(
'button_clicked',
properties: {
'button_id': 'login_button',
'user_type': 'premium',
'value': 29.99,
},
);
// Identify users (with optional traits)
await RybbitFlutter.instance.identify('user123', traits: {
'name': 'John Doe',
'plan': 'premium',
});
// Track outbound links (web URLs, deep links, app store links)
await RybbitFlutter.instance.trackOutboundLink(
'https://play.google.com/store/apps/details?id=com.example.app',
text: 'Download Our App',
);
// Track errors with context
try {
await riskyOperation();
} catch (e, stackTrace) {
await RybbitFlutter.instance.trackError(
'NetworkError',
'Failed to load user data: ${e.toString()}',
stackTrace: stackTrace.toString(),
fileName: 'user_service.dart',
lineNumber: 42,
);
}
Usage Examples
Configuration Options
const config = RybbitConfig(
apiKey: 'rb_your_api_key_here',
siteId: 'your_site_id',
// Optional: Custom analytics server
analyticsHost: 'https://analytics.yourcompany.com',
// Optional: Network and retry settings
requestTimeout: Duration(seconds: 15),
maxRetries: 5,
// Optional: Tracking behavior
trackScreenViews: true, // Auto-track route changes
trackAppLifecycle: true, // Track app foreground/background
trackQuerystring: true, // Include query parameters in pageviews
autoTrackPageview: true, // Track initial pageview on init
// Optional: Skip patterns (simple wildcards supported)
skipPatterns: [
'/debug/*', // Skip all debug pages
'/admin/internal/*', // Skip internal admin pages
'*/temp', // Skip any temp pages
],
// Optional: Offline queueing
enableOfflineQueue: true, // Persist events when offline (default: true)
maxQueueSize: 1000, // Max queued events before oldest are dropped
// Optional: Debug settings
enableLogging: false, // Debug logging
);
Manual Screen Tracking
If you prefer manual control over screen tracking:
// Disable automatic tracking and skip certain patterns
const config = RybbitConfig(
apiKey: 'rb_your_key',
siteId: 'your_site_id',
trackScreenViews: false,
skipPatterns: ['/debug/*', '/internal/*'],
);
// Track screens manually in your State class
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
RybbitFlutter.instance.trackPageView(
pathname: '/home',
pageTitle: 'Home Screen',
queryParams: {
'tab': 'featured',
'source': 'navigation',
},
);
}
}
E-commerce Tracking
// Track purchases
await RybbitFlutter.instance.trackEvent(
'purchase',
properties: {
'transaction_id': 'txn_123',
'revenue': 99.99,
'currency': 'USD',
'items': [
{
'item_id': 'prod_123',
'item_name': 'Premium Plan',
'category': 'subscription',
'quantity': 1,
'price': 99.99,
}
],
},
);
// Track cart actions
await RybbitFlutter.instance.trackEvent(
'add_to_cart',
properties: {
'item_id': 'prod_456',
'item_name': 'Widget Pro',
'category': 'widgets',
'value': 29.99,
},
);
Outbound Link Tracking
Note: Unlike the web SDK, outbound link tracking in Flutter requires explicit manual calls. This is because Flutter apps launch URLs programmatically (via url_launcher) rather than through DOM click events. Call trackOutboundLink() before launching URLs with launchUrl().
// Track external website visits
await RybbitFlutter.instance.trackOutboundLink(
'https://docs.flutter.dev',
text: 'Flutter Documentation',
);
// Track app store links
await RybbitFlutter.instance.trackOutboundLink(
'https://apps.apple.com/app/id123456789',
text: 'Download from App Store',
);
// Track deep links to other apps
await RybbitFlutter.instance.trackOutboundLink(
'instagram://user?username=yourcompany',
text: 'Follow on Instagram',
);
// Track email/phone links
await RybbitFlutter.instance.trackOutboundLink(
'mailto:support@example.com',
text: 'Contact Support',
);
// Track map/navigation links
await RybbitFlutter.instance.trackOutboundLink(
'https://maps.google.com/?q=coffee+near+me',
text: 'Find Coffee Nearby',
);
User Management
// Identify logged-in users with traits
await RybbitFlutter.instance.identify('user_12345', traits: {
'name': 'Jane Smith',
'email': 'jane@example.com',
'plan': 'premium',
});
// Update traits later without creating a new alias
await RybbitFlutter.instance.setTraits({
'plan': 'enterprise', // Update existing trait
'company': 'Acme Corp', // Add new trait
'old_field': null, // Remove a trait by setting to null
});
// Track user properties with events
await RybbitFlutter.instance.trackEvent(
'profile_updated',
properties: {
'plan_type': 'premium',
'account_age_days': 45,
'features_enabled': ['advanced_search', 'export'],
},
);
// Clear user ID on logout
RybbitFlutter.instance.clearUserId();
Error Tracking
// Track errors with full context
try {
await authenticateUser(credentials);
} catch (e, stackTrace) {
await RybbitFlutter.instance.trackError(
'AuthenticationError',
'Login failed: ${e.toString()}',
stackTrace: stackTrace.toString(),
fileName: 'auth_service.dart',
lineNumber: 156,
pathname: '/login',
pageTitle: 'Login Screen',
);
rethrow;
}
// Track different error types
await RybbitFlutter.instance.trackError(
'ValidationError',
'Email format is invalid',
fileName: 'validators.dart',
lineNumber: 23,
pathname: '/signup',
);
// Track network errors
await RybbitFlutter.instance.trackError(
'NetworkError',
'Request timeout after 30 seconds',
stackTrace: stackTrace?.toString(),
fileName: 'api_client.dart',
lineNumber: 89,
pathname: '/dashboard',
);
// Track custom business logic errors
await RybbitFlutter.instance.trackError(
'PaymentError',
'Insufficient funds for transaction',
fileName: 'payment_service.dart',
lineNumber: 234,
);
Offline Queueing
Events are persisted to local storage (Hive) when the device is offline and flushed automatically when connectivity is restored or the app resumes from the background. This happens transparently — no changes to your tracking calls are required.
// This event will be queued if the device is offline and sent later
await RybbitFlutter.instance.trackEvent('purchase_completed', properties: {
'order_id': 'ord_789',
'revenue': 49.99,
});
To disable offline queueing:
const config = RybbitConfig(
apiKey: 'rb_your_key',
siteId: 'your_site_id',
enableOfflineQueue: false,
);
To cap the queue at a lower number (e.g., for memory-constrained devices):
const config = RybbitConfig(
apiKey: 'rb_your_key',
siteId: 'your_site_id',
maxQueueSize: 100,
);
Note: The offline queue requires the
connectivity_plusplatform plugin. On Android this needs theACCESS_NETWORK_STATEpermission, which is automatically declared by the plugin.
Performance Tracking
// Track performance metrics with custom events
final stopwatch = Stopwatch()..start();
await loadData();
stopwatch.stop();
await RybbitFlutter.instance.trackEvent(
'data_load_performance',
properties: {
'duration_ms': stopwatch.elapsedMilliseconds,
'data_size': dataSize,
'cache_hit': wasCacheHit,
},
);
API Reference
RybbitFlutter
Methods
initialize(RybbitConfig config)- Initialize the SDK with configurationtrackPageView({required String pathname, String? pageTitle, String? referrer, Map<String, String>? queryParams})- Track a page/screen view with optional query parameterstrackEvent(String eventName, {Map<String, dynamic>? properties, String? pathname, String? pageTitle})- Track a custom eventtrackOutboundLink(String url, {String? text, String? pathname})- Track external link clickstrackError(String errorName, String message, {String? stackTrace, String? fileName, int? lineNumber, int? columnNumber, String? pathname, String? pageTitle})- Track application errors with contextidentify(String userId, {Map<String, dynamic>? traits})- Associate events with a user ID and optionally store custom traits on the serversetTraits(Map<String, dynamic> traits)- Update traits for the current identified user without creating a new aliasclearUserId()- Clear the current user IDdispose()- Clean up resources (call when app is disposed)
Query Parameters
The queryParams parameter accepts a Map<String, String> and automatically converts it to a proper query string format:
await RybbitFlutter.instance.trackPageView(
pathname: '/products',
queryParams: {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'spring_sale',
'category': 'electronics',
},
);
// Automatically becomes: ?utm_source=google&utm_medium=cpc&utm_campaign=spring_sale&category=electronics
Properties
isInitialized- Whether the SDK has been initializeduserId- Current user ID (if set)routeObserver- Route observer for automatic screen tracking
RybbitConfig
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey |
String | ✅ | - | Your Rybbit API key |
siteId |
String | ✅ | - | Your Rybbit site ID |
analyticsHost |
String | ❌ | https://app.rybbit.io |
Analytics server URL |
enableLogging |
bool | ❌ | false |
Enable debug logging |
requestTimeout |
Duration | ❌ | 10s |
Network request timeout |
maxRetries |
int | ❌ | 3 |
Max retry attempts |
trackScreenViews |
bool | ❌ | true |
Auto-track route changes |
trackAppLifecycle |
bool | ❌ | true |
Track app state changes |
trackQuerystring |
bool | ❌ | true |
Include query params in pageviews |
autoTrackPageview |
bool | ❌ | true |
Track initial pageview on init |
skipPatterns |
List | ❌ | [] |
URL patterns to skip (supports * wildcards) |
enableOfflineQueue |
bool | ❌ | true |
Persist events locally when offline and retry on reconnect |
maxQueueSize |
int | ❌ | 1000 |
Maximum events to hold in the offline queue |
Platform Support
| Platform | Support | Notes |
|---|---|---|
| ✅ Android | Full | Device info, screen metrics, deep links |
| ✅ iOS | Full | Device info, screen metrics, deep links |
| ✅ Web | Full | WASM support, full outbound link tracking |
| ✅ macOS | Full | Desktop support |
| ✅ Windows | Full | Desktop support |
| ✅ Linux | Full | Desktop support |
Requirements:
- Flutter 3.41.0 or higher
Troubleshooting
Common Issues
Events not appearing in dashboard:
- Verify your API key and Site ID are correct
- Check network connectivity
- Enable logging to see debug information
- Ensure you're calling
initialize()before tracking events
Route observer not working:
- Make sure you've added the route observer to
MaterialApp - Verify routes have
settings.namedefined - Check that
trackScreenViewsis enabled
Build errors:
- Run
flutter pub getafter adding the dependency - Check that your Flutter SDK version meets requirements (≥3.32.0)
- For web builds, ensure CORS is properly configured on your analytics server
Debug Mode
Enable debug logging to troubleshoot issues:
const config = RybbitConfig(
apiKey: 'rb_your_key',
siteId: 'your_site_id',
enableLogging: true,
);
This will print detailed information about:
- Initialization status
- Event tracking attempts
- Network requests and responses
- Error details
Contributing
Contributions are welcome! I have no specific contribution guide, but please raise an issue or PR with proper description
Development Setup
# Clone the repository
git clone https://github.com/stijnie2210/rybbit-flutter.git
cd rybbit-flutter
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run analysis
flutter analyze
Support
- 📖 Documentation: rybbit.io/docs
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
License
This project is licensed under the MIT License - see the LICENSE file for details.