# Integrating Multiple Analytics Services in Flutter: The Modular Way

> Implement a flexible analytics system in your Flutter app. This guide shows you how to manage multiple providers effortlessly.

URL: https://dinkomarinac.dev/blog/integrating-multiple-analytics-services-in-flutter-the-modular-way/
Author: Dinko Marinac
Published: 2024-07-29
Tags: tutorial, analytics, flutter, modular

## Introduction

In the world of mobile app development, analytics play a crucial role in understanding user behavior and making data-driven decisions. 

However, integrating analytics into your Flutter app can often lead to tightly coupled code and difficulty in switching between analytics providers. 

Migrating analytics is not like turning a switch and it takes time for data to settle in the new platforms, while at the same time, the data is still needed to make decisions.

To ease the migration and management of 2 (and possibly more platforms) I’ve used the following modular approach which I will show here with [Mixpanel](https://mixpanel.com/) and [PostHog](https://posthog.com/) as examples.

Ready to integrate some analytics?

> Full code can be found on [GitHub](https://github.com/dinko7/multiple-analytics-flutter).
> 

## Interface and event

To use multiple analytics services, we need to create a common interface so we can talk to each of the platforms in a unified way.

```dart
abstract class AnalyticsService {
  void track(AnalyticsEvent event);
  void identify(String userId);
  void reset();
}
```

This interface defines the core functionality we expect from any analytics service: tracking, identifying with the user upon login, and resetting upon logout.

Next, we need to define a generic event class:

```dart
abstract class AnalyticsEvent {
  String get eventName;
  Map<String, dynamic> get properties;
}
```

Let’s integrate this with our services.

## Concrete implementation

Before you start the implementation, make sure you follow the official guides on how to integrate [Mixpanel](https://docs.mixpanel.com/docs/tracking-methods/sdks/flutter) and [Posthog](https://posthog.com/docs/libraries/flutter).

Concrete implementations of these services are just proxy calls to the underlying platform.

```dart
class MixpanelAnalyticsService implements AnalyticsService {
  final Mixpanel _mixpanel;

  MixpanelAnalyticsService(this._mixpanel);

  @override
  void track(AnalyticsEvent event) {
    _mixpanel.track(event.eventName, properties: event.properties);
  }

  @override
  void identify(String userId) {
    _mixpanel.identify(userId);
  }

  @override
  void reset() {
    _mixpanel.reset();
  }
}

class PostHogAnalyticsService implements AnalyticsService {
  final Posthog _posthog;

  PostHogAnalyticsService(this._posthog);

  @override
  void track(AnalyticsEvent event) {
    _posthog.capture(
      eventName: event.eventName,
      properties: event.properties.map((key, value) => MapEntry(key, value as Object)),
    );
  }

  @override
  void identify(String userId) {
    _posthog.identify(userId: userId);
  }

  @override
  void reset() {
    _posthog.reset();
  }
}
```

To be able to swap out analytics on the fly or use multiple services at once, we need a service that will encapsulate all the services. Let’s call it `CompoundAnalyticsService`.

```dart
class CompoundAnalyticsService implements AnalyticsService {
  final List<AnalyticsService> _services;

  CompoundAnalyticsService(this._services);

  @override
  void track(AnalyticsEvent event) {
    for (var service in _services) {
      service.track(event);
    }
  }

  @override
  void identify(String userId) {
    for (var service in _services) {
      service.identify(userId);
    }
  }

  @override
  void reset() {
    for (var service in _services) {
      service.reset();
    }
  }
}
```

Additionally, if you are using a state management solution and feature flags, you can turn on and off particular analytics on the fly. Here’s an example with Riverpod:

```dart
final _mixpanelAnalyticsServiceProvider = Provider<AnalyticsService>((ref) {
  final mixpanel = ref.watch(mixpanelProvider);
  return MixpanelAnalyticsService(mixpanel);
});

final _posthogAnalyticsServiceProvider = Provider<AnalyticsService>((ref) {
  final posthog = ref.watch(posthogProvider);
  return PostHogAnalyticsService(posthog);
});

final analyticsServiceProvider = Provider<AnalyticsService>((ref) {
  final flags = ref.watch(featureFlagsProvider);
  return CompoundAnalyticsService([
    if (flags.enableMixpanel) ref.watch(_mixpanelAnalyticsServiceProvider),
    if (flags.enablePosthog) ref.watch(_posthogAnalyticsServiceProvider),
  ]);
});
```

## Usage

To start using all of this we need an event. Let’s say we want to share something in the app: a photo, video, or another app.

```dart
enum ShareEventItem { photo, video, app }

class ShareEvent implements AnalyticsEvent {
  final ShareEventItem item;

  ShareEvent({required this.item});

  @override
  String get eventName => 'Share';

  @override
  Map<String, dynamic> get properties => {
        'item': item.toString().split('.').last,
      };
}
```

Now, we can use our analytics service to track that even to any number of platforms like this:

```dart
class MyHomePage extends StatelessWidget {
  final AnalyticsService analyticsService;

  const MyHomePage({Key? key, required this.analyticsService}) : super(key: key);

  void _onShareItem(ShareEventItem item) {
    analyticsService.track(ShareEvent(item: item));
// Perform actual share action
  }

// Widget build method...
}

```

The benefits of this approach are:

1. Modularity: Easy to add or remove analytics providers without changing app logic
2. Type Safety: Events are defined as classes, providing compile-time checks
3. Separation of Concerns: Analytics logic is separate from business logic
4. Consistency: Ensures consistent event tracking across the app
5. Testability: Easy to mock analytics service for unit testing

## Conclusion

By implementing this modular approach to analytics in your Flutter app, you can enjoy greater flexibility, maintainability, and consistency in your analytics implementation. It allows you to easily switch between or combine different analytics providers, ensuring that your app's analytics strategy can evolve with your needs.

Remember, the key to successful analytics is not just in the implementation, but in defining meaningful events that provide actionable insights for your app's growth and improvement.

If you have found this useful, make sure to like and follow for more content like this. To know when the new articles are coming out, follow me on [**Twitter**](https://twitter.com/dinkomarinac) and [**LinkedIn**](https://www.linkedin.com/in/dinko-marinac/).

Until next time, happy coding!
