Skip to contentSkip to navigationSkip to topbar
On this page
Looking for more inspiration?Visit the
(information)
You're in the right place! Segment documentation is now part of Twilio Docs. The content you are used to is still here—just in a new home with a refreshed look.

Analytics-Flutter


(new)

Analytics-Flutter is in public beta

The Analytics-Flutter library is currently in public beta and is governed by Segment's First Access and Beta Preview Terms(link takes you to an external page). For more information, see the Analytics-Flutter GitHub repository(link takes you to an external page).

(warning)

Updated package for pilot users

If you've been using Analytics-Flutter since the pilot phase, see Upgrading from pilot to use the updated version of Analytics-Flutter.

Analytics-Flutter lets you add Segment analytics to your Flutter app.


Supported platforms

supported-platforms page anchor

Analytics-Flutter supports these platforms:

  • Android
  • iOS
  • MacOS
  • Web

Some destination plugins might not support all platform functionality. Refer to individual platform SDKs for more details.


To install Analytics-Flutter:

  1. Add the core package as a dependency.

    flutter pub add segment_analytics
  2. (Optional) Add any plugin that you need.

    flutter pub add segment_analytics_plugin_firebase
  3. Import the library in your Dart code.

    import 'package:segment_analytics/client.dart';
  4. Add permissions to AndroidManifest.xml. Add the following line between the `` tags.

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

The Flutter SDK package exposes a method called createClient which you can use to create the Segment Analytics client. This central client manages all of the tracking events. Segment recommends that you add this as a property on your main app's state class.

1
const writeKey = 'SEGMENT_API_KEY';
2
final analytics = createClient(Configuration(writeKey));

You must pass the writeKey.

These are the options you can apply to configure the client:

Option NameDefaultDescription
writeKey (required)''Your Segment API key.
debugfalseWhen this is set to false, it won't generate any info logs.
collectDeviceIdfalseSet this to true to automatically collect the device ID from the DRM API on Android devices. On Apple platforms it will collect the identifierForVendor value if available.
flushPoliciescount=30, time=20sList of flush policies controlling when to send batches of events to the plugins
apiHostapi.segment.io/v1Used to specify the regional Segment event endpoint.
cdnHostcdn-settings.segment.com/v1Used to specify the regional Segment settings endpoint.
errorHandlernullCustom error handler. By default, this logs errors to the standard flutter logger.
trackApplicationLifecycleEventsfalseSet this to true to enable automatic tracking for app lifecycle events which include, application installed, opened, updated, backgrounded.
trackDeeplinksfalseSet this to true to enable automatic tracking for when the user opens the app through a deep link. Note: When you send this flag, the SDK plugin_appsflyer ignores onAppOpenAttribution(link takes you to an external page).
autoAddSegmentDestinationtrueSet this to false to skip adding the SegmentDestination plugin.
defaultIntegrationSettingsnullPlugin settings that are used if the request to get the settings from Segment fails.
maxBatchSizetrueThe maximum number of events you can send to the API at once is 100.
appStateStreamnullSet this to override the stream of application foreground or background events.
requestFactorytrueSet this to override the factory to generate HTTP requests. Type: RequestFactory(link takes you to an external page).

If you've been using Analytics-Flutter since the pilot phase, follow these steps to use the upgraded version of Analytics-Flutter as Segment renamed the package of the library from analytics to segment_analytics.

  1. Remove the analytics package and use segment_analytics in your pubspec.yaml file.

    1
    - analytics:
    2
    - git:
    3
    - url: https://github.com/segmentio/analytics_flutter
    4
    - ref: main
    5
    - path: packages/core
    6
    + segment_analytics: ^1.0.1
  2. Change the imports from package:analytics to package:segment_analytics in your dart files.

    1
    - import 'package:analytics/client.dart';
    2
    + import 'package:segment_analytics/client.dart';

Once you've installed the Analytics-Flutter library, you can start collecting data through Segment's tracking methods:


The Track method is how you record any actions your users perform, along with any properties that describe the action.

Method signatureExample use
Future track(String event: string, {Map<String, dynamic>? properties});

The Screen method lets you record whenever a user sees a screen in your mobile app, along with any properties about the screen.

Method signatureExample use
Future screen(String name: string, {Map<String, dynamic>? properties});

See how to set up automatic screen tracking.


The Identify method lets you tie a user to their actions and record traits about them. This includes a unique user ID and any optional traits you know about them like their email, name, address. The traits option can include any information you might want to tie to the user, but when using any of the reserved user traits, you should make sure to only use them for their intended meaning. All reserved traits are strongly typed by the UserTraits class. When you use traits not listed as a reserved user trait, these go under the custom property.

Method signatureExample use
Future identify({String? userId, UserTraits? userTraits});

The Group method is how you associate an individual user with a group — whether it's a company, organization, account, project, or team. This includes a unique group ID and any optional group traits you know about them like the company name, industry, or the number of employees. The traits option can include any information you might want to tie to the group, but when using any of the reserved group traits, you should make sure to only use them for their intended meaning. All reserved traits are strongly typed by the GroupTraits class. When you use traits not listed as a reserved user trait, these go under the custom property.

Method signatureExample use
Future group(String groupId, {GroupTraits? groupTraits});

The Analytics-Flutter utility methods help you work with plugins from the analytics timeline. They include:


The Alias method is used to merge two user identities, effectively connecting two sets of user data as one. This is an advanced method, but it's required to manage user identities successfully in some of Segment's destinations.

Method signatureExample use
Future alias(String newUserId);

The Reset method clears the internal state of the library for the current user and group. This is useful for apps where users can log in and out with different identities over time.

Note that each time you call Reset, a new AnonymousId generates automatically.

Method signatureExample use
void reset();

By default, the analytics send to the API after 30 seconds or when 20 items accumulate, whichever happens first, and whenever the app resumes if the user has closed the app with some events unsent. You can modify these values by the flushAt and flushInterval config options. You can also trigger a flush event manually.

Method signatureExample use
Future flush();

In case you need to reinitialize the client, because you called createClient more than once for the same client in your application lifecycle, use this method on the old client to clear any subscriptions and timers first.

1
var analytics = createClient(Configuration(writeKey));
2
3
analytics.cleanup();
4
5
analytics = createClient(Configuration(writeKey));

If you don't do this, the old client instance still exists and retains the timers, which makes all of your events fire twice.


Automatic screen tracking

automatic-screen-tracking page anchor

Automatic screen tracking enables you to track navigation globally, as sending a Screen event with each navigation action gets tiresome quickly. To set up automatic screen tracking, you need to add the analytics navigator observer to your app's navigator observers. For example, if you're using the MaterialApp class, add the following:

1
return MaterialApp(navigatorObservers: [
2
ScreenObserver()
3
]);

Segment's plugin architecture enables you to modify and augment how the analytics client works. You have complete control over how the events process before being uploaded to the Segment API. From modifying event payloads to changing analytics functionality, plugins help to speed up the process of getting things done.

In order to customize what happens after an event is created, you can create and place various plugins along the processing pipeline that an event goes through. This pipeline is referred to as a timeline.

As plugins run through a timeline, they execute in order of insertion based on their entry types. Segment has these five entry types:

Plugin TypeDescription
beforeExecutes before event processing begins.
enrichmentExecutes as the first level of event processing.
destinationExecutes as events begin to pass off to destinations.
afterExecutes after all event processing completes. This can be used to perform cleanup operations.
utilityExecutes only with manual calls such as Logging.

Plugins can have their own native code (for example, the iOS-only analytics_plugin_idfa) or wrap an underlying library (such as analytics_plugin_firebase which uses firebase_core and firebase_analytics under the hood).


Segment is included as a DestinationPlugin out of the box. You can add as many destination plugins as you like and upload events and data to them.

You can pass autoAddSegmentDestination = false in the options when setting up your client to prevent the SegmentDestination plugin from being added automatically.


You can add a plugin at any time through the Add method.

1
import 'package:segment_analytics/client.dart';
2
import 'package:segment_analytics/event.dart';
3
import 'package:segment_analytics/state.dart';
4
import 'package:segment_analytics_plugin_advertising_id/plugin_advertising_id.dart';
5
import 'package:segment_analytics_plugin_idfa/plugin_idfa.dart';
6
import 'package:segment_analytics_plugin_firebase/plugin_firebase.dart'
7
show FirebaseDestination;
8
9
const writeKey = 'SEGMENT_API_KEY';
10
11
class _MyAppState extends State<MyApp> {
12
final analytics = createClient(Configuration(writeKey));
13
14
@override
15
void initState() {
16
super.initState();
17
initPlatformState();
18
19
analytics
20
.addPlugin(FirebaseDestination(DefaultFirebaseOptions.currentPlatform));
21
analytics.addPlugin(PluginAdvertisingId());
22
analytics.addPlugin(PluginIdfa());
23
}
24
}

Writing your own plugins

writing-your-own-plugins page anchor

Plugins are implemented by extending one of the provided plugin classes. The available plugin classes are:

  • Plugin
  • EventPlugin
  • DestinationPlugin
  • UtilityPlugin
  • PlatformPlugin

Any plugin must be an extension of one of these classes.

You can then customize the functionality by overriding different methods on the base class. For example, here is a Logger plugin:

1
import 'dart:convert';
2
3
import 'package:segment_analytics/analytics.dart';
4
import 'package:segment_analytics/event.dart';
5
import 'package:segment_analytics/plugin.dart';
6
import 'package:segment_analytics/logger.dart';
7
8
class EventLogger extends DestinationPlugin {
9
var logKind = LogFilterKind.debug;
10
11
EventLogger() : super("event_logger");
12
13
@override
14
void configure(Analytics analytics) {
15
pAnalytics = analytics;
16
}
17
18
@override
19
Future<RawEvent?>? execute(RawEvent event) async {
20
log("${event.type.toString().toUpperCase()} event${event is TrackEvent ? " (${event.event})" : ''} saved: \n${jsonEncode(event.toJson())}",
21
kind: logKind);
22
return event;
23
}
24
}

As it overrides the execute method, this Logger calls log for every event going through the timeline.


You can use these plugins to meet your tracking needs:


Controlling upload with flush policies

controlling-upload-with-flush-policies page anchor

You can use FlushPolicies to more granularly control when events upload.

A flush policy defines the strategy for deciding when to flush. This can be on an interval, on a certain time of day, after receiving a certain number of events, or even after receiving a particular event. This gives you more flexibility on when to send events to Segment.

To make use of flush policies, you can set them in the configuration of the client:

1
import 'package:segment_analytics/flush_policies/count_flush_policy.dart';
2
import 'package:segment_analytics/flush_policies/timer_flush_policy.dart';
3
4
final analytics = createClient(Configuration(/*...*/, flushPolicies: [
5
CountFlushPolicy(10),
6
TimerFlushPolicy(100000)
7
]));

You can set several policies at a time. Whenever any policy decides it's time for a flush, it triggers an upload of the events. The rest are reset so that their logic restarts after every flush.

This means only the first policy to reach shouldFlush gets to trigger a flush at a time. In the example above, when either the event count gets to 5 or the timer reaches 500ms, whatever comes first triggers a flush.

Segment has several standard FlushPolicies:

  • CountFlushPolicy triggers whenever a certain number of events is reached.
  • TimerFlushPolicy triggers on an interval of milliseconds.
  • StartupFlushPolicy triggers on client startup only.

Adding or removing policies

adding-or-removing-policies page anchor

One of the main advantanges of FlushPolicies is that you can add and remove policies whenever you want. This is powerful when you want to reduce or increase the amount of flushes.

For example, you might want to disable flushes if you detect the user has no network:

1
if (isConnected) {
2
analytics.addFlushPolicy(policiesIfNetworkIsUp);
3
} else {
4
analytics.removeFlushPolicy(policiesIfNetworkIsUp)
5
}

Creating your own flush policies

creating-your-own-flush-policies page anchor

You can create a custom FlushPolicy for your application needs by implementing the FlushPolicy interface. You can also extend the FlushPolicyBase class that already creates and handles the shouldFlush value reset.

A FlushPolicy only needs to implement one method:

  • onEvent(RawEvent event): Gets called on every event tracked by your client.

A FlushPolicy can optionally implement:

  • reset(): Calls after a flush is triggered either by your policy, by another policy, or manually.
  • start(): Executes when the flush policy is enabled and added to the client. This is a good place to start background operations, make async calls, and configure things before execution.

The FlushPolicy should have a shouldFlush boolean value. When this is set to true, the client attempts to upload events. Each policy should reset this value to false according to its own logic, although it's pretty common to do it inside the reset method.

1
import 'package:segment_analytics/event.dart';
2
import 'package:segment_analytics/flush_policies/flush_policy.dart';
3
4
class FlushOnScreenEventsPolicy extends FlushPolicy {
5
6
@override
7
onEvent(RawEvent event) {
8
// Only flush when a screen even happens
9
if (event is ScreenEvent) {
10
this.shouldFlush = true;
11
}
12
}
13
14
@override
15
reset() {
16
// Superclass will reset the shouldFlush value so that the next screen event triggers a flush again
17
// But you can also reset the value whenever, say another event comes in or after a timeout
18
super.reset();
19
}
20
}

By default, any logging is done through the standard Flutter logging mechanism. To customize logging, you can build your own logger, which must implement the LogTarget mixin. For example:

1
import 'package:segment_analytics/logger.dart';
2
3
void customDebugLog(String msg) {
4
// ...
5
}
6
7
void customWarningLog(String msg) {
8
// ...
9
}
10
11
void customErrorLog(String msg) {
12
// ...
13
}
14
15
class CustomLogger with LogTarget {
16
@override
17
void parseLog(LogMessage log) {
18
switch (log.kind) {
19
case LogFilterKind.debug:
20
customDebugLog("Segment: ${log.message}");
21
break;
22
case LogFilterKind.warning:
23
customWarningLog("Segment: ${log.message}");
24
break;
25
case LogFilterKind.error:
26
customErrorLog("Segment: ${log.message}");
27
break;
28
}
29
}
30
}
31
32
// Set the default logger to use the CustomLogger
33
LogFactory.logger = CustomLogger();

You can handle analytics client errors through the errorHandler option.

The error handler configuration receives a function which gets called whenever an error happens on the analytics client. It receives an Exception that extends one of the errors from errors.dart(link takes you to an external page).

You can use this error handling to trigger different behaviors in the client when a problem occurs. For example, if the client gets rate limited, you could use the error handler to swap flush policies to be less aggressive.

1
import 'package:segment_analytics/errors.dart';
2
3
//...
4
5
final flushPolicies = [CountFlushPolicy(5), TimerFlushPolicy(500)];
6
7
void errorHandler(Exception error) {
8
if (error is NetworkServerLimited) {
9
// Remove all flush policies
10
analytics.removeFlushPolicy(analytics.getFlushPolicies());
11
// Add less persistent flush policies
12
analytics.addFlushPolicy([
13
CountFlushPolicy(100),
14
TimerFlushPolicy(5000)
15
]);
16
}
17
}
18
19
final analytics = createClient(Configuration(writeKey),
20
errorHandler: errorHandler,
21
flushPolicies: flushPolicies);

Reporting errors from plugins

reporting-errors-from-plugins page anchor

Plugins can also report errors to the handler by using the .error(link takes you to an external page) function of the analytics client. Segment recommends you to use the PluginError for consistency, and to attach the innerError with the actual exception that was hit.

1
import 'package:segment_analytics/errors.dart';
2
3
//...
4
5
try {
6
distinctId = await mixpanel.getDistinctId();
7
} catch (e) {
8
analytics.error(
9
PluginError('Error: Mixpanel error calling getDistinctId', e)
10
);
11
}


analytics_flutter on web checks for Analytics.JS userInfo cookies/localStorage and reuses the anonymousId data.

LocalStorage recovery only works when running in the same domain/subdomain.


See the example app(link takes you to an external page) to check a full test app of how to integrate Analytics-Flutter into your own Flutter app.