IForEvents - Core Package
A comprehensive Flutter package for event tracking and analytics integration. IForEvents provides a unified interface for multiple analytics platforms while automatically collecting device information and user data.
Features
- π Multi-platform Analytics: Support for Firebase Analytics, Mixpanel, Algolia, CleverTap, and Meta
 - π± Cross-platform: Works on Android, iOS, and Windows
 - π Automatic Device Detection: Collects device information automatically
 - π IP Detection: Automatic IP address detection
 - π― Event Tracking: Simple event tracking with custom properties
 - π€ User Identification: User identification with custom data
 - π Route Tracking: Automatic screen/route tracking
 - ποΈ Modular Architecture: Add only the integrations you need
 - π§ Extensible: Create custom integrations easily
 
Supported Integrations
| Integration | Package | Description | Native Config Required | 
|---|---|---|---|
| IForevents API | iforevents | 
Native integration with the IForevents backend | β No | 
| Firebase Analytics | iforevents_firebase | 
Google Firebase Analytics integration | β Yes | 
| Mixpanel | iforevents_mixpanel | 
Mixpanel analytics integration | β No | 
| Algolia Insights | iforevents_algolia | 
Algolia search analytics integration | β No | 
| CleverTap | iforevents_clevertap | 
CleverTap engagement platform integration | β Yes | 
| Meta (Facebook) | iforevents_meta | 
Facebook App Events integration | β Yes | 
Installation
Add this to your package's pubspec.yaml file:
dependencies:
  iforevents: ^0.0.2
  # Add the integrations you need
  iforevents_firebase: ^0.0.1    # For Firebase Analytics
  iforevents_mixpanel: ^0.0.1    # For Mixpanel
  iforevents_algolia: ^0.0.1     # For Algolia Insights
  iforevents_clevertap: ^0.0.1   # For CleverTap
  iforevents_meta: ^0.0.1        # For Meta/Facebook
Then run:
flutter pub get
Quick Start
1. Import the packages
import 'package:iforevents/iforevents.dart';
import 'package:iforevents_firebase/iforevents_firebase.dart';
import 'package:iforevents_mixpanel/iforevents_mixpanel.dart';
2. Initialize with your integrations
final iforevents = Iforevents();
await iforevents.init(integrations: [
  const FirebaseIntegration(),
  const MixpanelIntegration(token: 'YOUR_MIXPANEL_TOKEN'),
]);
3. Identify users
await iforevents.identify(
  event: IdentifyEvent(
    customID: 'user123',
    properties: {
      'email': 'user@example.com',
      'name': 'John Doe',
      'plan': 'premium',
    },
  ),
);
4. Track events
iforevents.track(
  event: TrackEvent(
    eventName: 'button_clicked',
    properties: {
      'button_name': 'signup',
      'screen': 'home',
    },
  ),
);
Usage
Initialization
Initialize IforEvents with the analytics integrations you want to use:
import 'package:iforevents/iforevents.dart';
import 'package:iforevents_firebase/iforevents_firebase.dart';
import 'package:iforevents_mixpanel/iforevents_mixpanel.dart';
final iforevents = Iforevents();
await iforevents.init(integrations: [
  const FirebaseIntegration(),
  const MixpanelIntegration(token: 'your_mixpanel_project_token'),
]);
User Identification
Identify users with custom data. Device information is automatically included:
await iforevents.identify(
  event: IdentifyEvent(
    customID: 'user_123',
    properties: {
      'email': 'john.doe@example.com',
      'name': 'John Doe',
      'age': 30,
      'subscription': 'premium',
      'signup_date': '2023-01-15',
    },
  ),
);
The following device data is automatically collected and included:
- IP address
 - Device brand and model
 - OS version
 - App version
 - Platform (Android/iOS/Windows)
 - Unique device identifier
 
Event Tracking
Track custom events with properties:
// Simple event
iforevents.track(
  event: TrackEvent(eventName: 'app_opened'),
);
// Event with properties
iforevents.track(
  event: TrackEvent(
    eventName: 'purchase_completed',
    properties: {
      'product_id': 'prod_123',
      'price': 29.99,
      'currency': 'USD',
      'category': 'premium_features',
    },
  ),
);
// Different event types
iforevents.track(
  event: TrackEvent(
    eventName: 'page_view',
    eventType: EventType.screen,
    properties: {
      'page_name': 'product_details',
      'product_id': 'prod_123',
    },
  ),
);
Screen/Route Tracking
Automatically track screen navigation:
await iforevents.screen(
  toRoute: RouteSettings(name: '/product_details'),
  previousRoute: RouteSettings(name: '/home'),
);
Navigation Observer
Use the built-in navigator observer for automatic route tracking:
import 'package:iforevents/utils/navigator_observer.dart';
MaterialApp(
  navigatorObservers: [
    IforeventsNavigatorObserver(iforevents: iforevents),
  ],
  // ... rest of your app
)
Reset User Data
Reset user identification and clear stored data:
await iforevents.reset();
Creating Custom Integrations
You can create your own analytics integrations by extending the Integration class. This allows you to add support for any analytics platform not currently supported.
Basic Custom Integration
import 'package:iforevents/iforevents.dart';
class CustomAnalyticsIntegration extends Integration {
  final String apiKey;
  final String endpoint;
  
  const CustomAnalyticsIntegration({
    required this.apiKey,
    required this.endpoint,
  });
  @override
  Future<void> init() async {
    // IMPORTANT: Always call super.init() first
    await super.init();
    
    // Initialize your analytics SDK here
    print('Initializing custom analytics with API key: $apiKey');
    
    // Example: Initialize SDK
    // await CustomAnalyticsSDK.initialize(apiKey);
  }
  @override
  Future<void> identify({required IdentifyEvent event}) async {
    // IMPORTANT: Always call super.identify() first
    await super.identify(event: event);
    
    // Handle user identification
    print('Identifying user: ${event.customID}');
    
    // Example: Set user properties
    // await CustomAnalyticsSDK.setUserId(event.customID);
    // await CustomAnalyticsSDK.setUserProperties(event.properties);
  }
  @override
  Future<void> track({required TrackEvent event}) async {
    // IMPORTANT: Always call super.track() first
    await super.track(event: event);
    
    // Handle event tracking
    print('Tracking event: ${event.eventName}');
    
    // Example: Track event
    // await CustomAnalyticsSDK.track(
    //   event.eventName,
    //   properties: event.properties,
    // );
  }
  @override
  Future<void> reset() async {
    // IMPORTANT: Always call super.reset() first
    await super.reset();
    
    // Handle user data reset
    print('Resetting custom analytics data');
    
    // Example: Reset user data
    // await CustomAnalyticsSDK.reset();
  }
  @override
  Future<void> pageView({required PageViewEvent event}) async {
    // IMPORTANT: Always call super.pageView() first
    await super.pageView(event: event);
    
    // Handle page view tracking
    if (event.toRoute?.name != null) {
      print('Page view: ${event.toRoute!.name}');
      print('Navigation type: ${event.navigationType}');
      
      // Example: Track page view
      // await CustomAnalyticsSDK.trackPageView(event.toRoute!.name!);
    }
  }
}
β οΈ CRITICAL: @mustCallSuper Requirement
All Integration methods are marked with
@mustCallSuper, which means you MUST call the parent method first in your override. This ensures that any callback functions (onInit, onIdentify, onTrack, onReset, onPageView) are executed properly.Failure to call
super.method()will result in missing functionality and potential bugs.
Advanced Custom Integration with HTTP API
Here's an example of a custom integration that sends data to a REST API:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:iforevents/iforevents.dart';
class HTTPAnalyticsIntegration extends Integration {
  final String baseUrl;
  final String apiKey;
  final Map<String, String> headers;
  final bool enableLogging;
  
  const HTTPAnalyticsIntegration({
    required this.baseUrl,
    required this.apiKey,
    this.headers = const {},
    this.enableLogging = false,
  });
  String? _userId;
  @override
  Future<void> init() async {
    if (enableLogging) {
      print('HTTP Analytics Integration initialized');
      print('Base URL: $baseUrl');
    }
  }
  @override
  Future<void> identify({required IdentifyEvent event}) async {
    _userId = event.customID;
    
    try {
      final response = await http.post(
        Uri.parse('$baseUrl/identify'),
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer $apiKey',
          ...headers,
        },
        body: jsonEncode({
          'user_id': event.customID,
          'properties': event.properties,
          'timestamp': DateTime.now().toIso8601String(),
        }),
      );
      
      if (enableLogging) {
        print('Identify response: ${response.statusCode}');
      }
    } catch (e) {
      if (enableLogging) {
        print('Error identifying user: $e');
      }
    }
  }
  @override
  Future<void> track({required TrackEvent event}) async {
    try {
      final payload = {
        'event': event.eventName,
        'properties': event.properties,
        'timestamp': DateTime.now().toIso8601String(),
      };
      
      if (_userId != null) {
        payload['user_id'] = _userId!;
      }
      
      final response = await http.post(
        Uri.parse('$baseUrl/track'),
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer $apiKey',
          ...headers,
        },
        body: jsonEncode(payload),
      );
      
      if (enableLogging) {
        print('Track event response: ${response.statusCode}');
      }
    } catch (e) {
      if (enableLogging) {
        print('Error tracking event: $e');
      }
    }
  }
  @override
  Future<void> reset() async {
    _userId = null;
    
    if (enableLogging) {
      print('HTTP Analytics data reset');
    }
  }
  @override
  Future<void> pageView({
    required RouteSettings? toRoute,
    required RouteSettings? previousRoute,
  }) async {
    if (toRoute?.name != null) {
      await track(
        event: TrackEvent(
          eventName: 'page_view',
          eventType: EventType.screen,
          properties: {
            'page_name': toRoute!.name!,
            'previous_page': previousRoute?.name,
          },
        ),
      );
    }
  }
}
Using Custom Integrations
Once you've created your custom integration, use it just like any other integration:
await iforevents.init(integrations: [
  // Built-in integrations
  const FirebaseIntegration(),
  const MixpanelIntegration(token: 'your_token'),
  
  // Your custom integrations
  const CustomAnalyticsIntegration(
    apiKey: 'your_api_key',
    endpoint: 'https://api.your-analytics.com',
  ),
  const HTTPAnalyticsIntegration(
    baseUrl: 'https://api.your-service.com',
    apiKey: 'your_api_key',
    enableLogging: true,
  ),
]);
Integration Best Practices
- Error Handling: Always wrap SDK calls in try-catch blocks
 - Async Operations: Use async/await for all network and SDK operations
 - Validation: Validate input data before sending to analytics services
 - Logging: Provide optional logging for debugging
 - Configuration: Make integrations configurable with constructor parameters
 - Null Safety: Handle null values appropriately
 - Performance: Avoid blocking the UI thread with heavy operations
 
Testing Custom Integrations
Create unit tests for your custom integrations:
import 'package:flutter_test/flutter_test.dart';
import 'package:iforevents/iforevents.dart';
void main() {
  group('CustomAnalyticsIntegration', () {
    late CustomAnalyticsIntegration integration;
    
    setUp(() {
      integration = const CustomAnalyticsIntegration(
        apiKey: 'test_key',
        endpoint: 'https://test.com',
      );
    });
    
    test('should initialize without errors', () async {
      await expectLater(integration.init(), completes);
    });
    
    test('should identify users', () async {
      final event = IdentifyEvent(
        customID: 'test_user',
        properties: {'email': 'test@example.com'},
      );
      
      await expectLater(
        integration.identify(event: event),
        completes,
      );
    });
    
    test('should track events', () async {
      final event = TrackEvent(
        eventName: 'test_event',
        properties: {'key': 'value'},
      );
      
      await expectLater(
        integration.track(event: event),
        completes,
      );
    });
  });
}
Device Information
IforEvents automatically collects comprehensive device information:
Android
- Device ID (Android ID)
 - Brand and model
 - OS version (SDK version)
 - Physical device detection
 - App version and build info
 
iOS
- Identifier for vendor
 - Device name and model
 - iOS version
 - Physical device detection
 - App version and build info
 
Windows
- Device ID
 - Computer name
 - Windows version and build
 - App version info
 
API Reference
Iforevents Class
Methods
init({List<Integration> integrations})- Initialize with analytics integrationsidentify({required IdentifyEvent event})- Identify user with custom datatrack({required TrackEvent event})- Track eventsscreen({required RouteSettings? toRoute, required RouteSettings? previousRoute})- Track screen navigationreset()- Reset user data and clear stored information
Static Properties
ip- Get current IP addressdeviceData- Get comprehensive device information
EventType Enum
EventType.track- Standard tracking eventEventType.screen- Screen view eventEventType.alias- User alias event
Integration Class
Base class for creating custom integrations. All methods are marked with @mustCallSuper, which means you must call the parent method first in your override:
abstract class Integration<T> {
  const Integration({
    this.onInit,
    this.onIdentify, 
    this.onTrack,
    this.onReset,
    this.onPageView,
  });
  // Override these methods in your custom integration
  // IMPORTANT: Always call super.method() first due to @mustCallSuper
  @mustCallSuper
  Future<void> init() async {}
  
  @mustCallSuper
  Future<void> identify({required IdentifyEvent event}) async {}
  
  @mustCallSuper
  Future<void> track({required TrackEvent event}) async {}
  
  @mustCallSuper
  Future<void> reset() async {}
  
  @mustCallSuper
  Future<void> pageView({required PageViewEvent event}) async {}
}
β οΈ CRITICAL: @mustCallSuper Requirement
All Integration methods are marked with
@mustCallSuper, which means you MUST call the parent method first in your override. Failure to do so will result in missing functionality and potential bugs.
Integration Guides
For detailed setup instructions for each integration, see their respective README files:
- Firebase Integration - Requires native configuration
 - Mixpanel Integration - No native configuration required
 - Algolia Integration - No native configuration required
 - CleverTap Integration - Requires native configuration
 - Meta Integration - Requires native configuration
 
Example
Check out the example directory for a complete implementation showing:
- Multi-integration setup
 - User identification flow
 - Event tracking examples
 - Navigation tracking
 - Error handling
 - Custom integration examples
 
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Clone the repository:
 
git clone https://github.com/innovafour/flutter_iforevents.git
cd flutter_iforevents
- Install dependencies:
 
flutter pub get
- Run tests:
 
flutter test
Support
- π§ Email: support@innovafour.com
 - π Issues: GitHub Issues
 - π Documentation: API Documentation
 
License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ by Innovafour