| title | Flutter | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sidebarTitle | Flutter | ||||||||||||||||||||
| sidebar | Docs | ||||||||||||||||||||
| showTitle | true | ||||||||||||||||||||
| github | https://github.com/PostHog/posthog-flutter | ||||||||||||||||||||
| platformLogo | flutter | ||||||||||||||||||||
| features |
|
import FlutterIdentify from './_snippets/identify.mdx'
This is an optional library you can install if you're working with Flutter. It uses an internal queue to make calls fast and non-blocking. It also batches requests and flushes asynchronously, making it perfect to use in any part of your mobile app.
PostHog supports the iOS, macOS, Android, and Web platforms.
Installation
import FlutterInstall from '../../integrate/_snippets/install-flutter.mdx'
Capturing events
import FlutterSendEvents from '../../integrate/send-events/_snippets/send-events-flutter.mdx'
Identifying users
We highly recommend reading our section on Identifying users to better understand how to correctly use this method.
Get the current user's distinct ID
You may find it helpful to get the current user's distinct ID. For example, to check whether you've already called identify for a user or not.
To do this, call Posthog().getDistinctId(). This returns either the ID automatically generated by PostHog or the ID that has been passed by a call to identify().
Alias
Sometimes, you want to assign multiple distinct IDs to a single user. This is helpful when your primary distinct ID is inaccessible. For example, if a distinct ID used on the frontend is not available in your backend.
In this case, you can use alias to assign another distinct ID to the same user.
await Posthog().alias( alias: 'distinct_id', );
We strongly recommend reading our docs on alias to best understand how to correctly use this method.
Anonymous vs identified events
import IdentifiedVsAnonymousIntro from '../../product-analytics/_snippets/identified-vs-anonymous-intro.mdx'
How to capture anonymous events
import HowToCaptureAnonymousEventsFlutter from '../../product-analytics/_snippets/how-to-capture-anonymous-events-flutter.mdx'
How to capture identified events
import HowToCaptureIdentifiedEventsFlutter from '../../product-analytics/_snippets/how-to-capture-identified-events-flutter.mdx'
Super properties
Super properties are properties associated with events that are set once and then sent with every capture call, be it a $screen, or anything else.
They are set using Posthog().register, which takes a key and value, and they persist across sessions.
For example, take a look at the following call:
import 'package:posthog_flutter/posthog_flutter.dart'; await Posthog().register("team_id", 22);
The call above ensures that every event sent by the user will include "team_id": 22. This way, if you filtered events by property using team_id = 22, it would display all events captured on that user after the Posthog().register call, since they all include the specified super property.
However, please note that this does not store properties against the User, only against their events. To store properties against the User object, you should use Posthog().identify. More information on this can be found on the Sending User Information section.
Removing stored super properties
Super properties are persisted across sessions so you have to explicitly remove them if they are no longer relevant. In order to stop sending a super property with events, you can use Posthog().unregister, like so:
import 'package:posthog_flutter/posthog_flutter.dart'; await Posthog().unregister("team_id");
This will remove the super property and subsequent events will not include it.
If you are doing this as part of a user logging out you can instead simply use Posthog().reset() which takes care of clearing all stored super properties and more.
Group analytics
Group analytics allows you to associate the events for that person's session with a group (e.g. teams, organizations, etc.). See Group Analytics for Flutter examples and implementation details.
Note: This is a paid feature and is not available on the open-source or free cloud plan. Learn more on the pricing page.
Feature flags
import FeatureFlagsLibsIntro from "../_snippets/feature-flags-libs-intro.mdx"
import FlutterFeatureFlagsCode from '../../integrate/feature-flags-code/_snippets/feature-flags-code-flutter.mdx'
Bootstrapping flags
import BootstrappingIntro from "../../feature-flags/snippets/bootstrapping-intro.mdx" import MobileBootstrapBehavior from "../_snippets/mobile-bootstrap-behavior.mdx"
Set config.bootstrap before calling setup() to seed identity and flag values before the first /flags response (requires the Flutter SDK 5.31.0+):
final config = PostHogConfig('<ph_project_token>'); config.host = '<ph_client_api_host>'; config.bootstrap = PostHogBootstrapConfig( distinctId: 'distinct_id_of_your_user', isIdentifiedId: true, featureFlags: { 'flag-1': true, 'variant-flag': 'control', }, ); await Posthog().setup(config);
The values are forwarded to the native iOS and Android SDKs:
On Flutter web, bootstrap is not applied, so configure it in your posthog.init({...}) snippet instead. See the SDK bootstrapping guide for the cross-SDK overview.
Setting properties for flag evaluation
If a flag targets person or group properties, you can send those properties inline with the next flag evaluation request instead of waiting for a $set event to be ingested. This avoids the race where a flag returns a stale value right after you set a property.
// Person properties — included in the next flag evaluation request await Posthog().setPersonPropertiesForFlags({ 'storefront_country': 'US', 'is_beta_user': true, }); // Group properties await Posthog().setGroupPropertiesForFlags('company', {'plan': 'enterprise'});
By default these reload feature flags, and the returned Future completes once the reload finishes, so the next getFeatureFlag reflects the new properties. Pass reloadFeatureFlags: false to set several properties before reloading. Use resetPersonPropertiesForFlags() and resetGroupPropertiesForFlags() to clear them. See property overrides for flag evaluation for details.
Experiments (A/B tests)
Since experiments use feature flags, the code for running an experiment is very similar to the feature flags code. See feature flag code examples for Flutter implementation details.
It's also possible to run experiments without using feature flags.
Error tracking
To set up error tracking in your project, see the error tracking docs.
Logs
To set up logs in your Flutter app, follow the Flutter logs installation guide. The SDK exposes Posthog().logger.{trace,debug,info,warn,error,fatal} (and Posthog().captureLog for full control) for sending structured records to PostHog Logs, with batching, offline persistence, and a rate cap built in.
Session replay
Note: Session replay is supported on Flutter Web, Android, and iOS.
To set up session replay web or mobile session replay in your project, all you need to do is install the Flutter SDK, follow the additional installation instructions, and enable "Record user sessions" in your project settings and enable the sessionReplay option.
If you're using Flutter Web, also enable the Canvas capture in your project settings. This is needed as Flutter renders your app using a browser canvas element.
On Flutter Web, masking (maskAllTexts, maskAllImages, PostHogMaskWidget) applies inside that canvas too — declare session_recording.canvasCapture.maskRegionsFn in the posthog.init call in your web/index.html to enable it (requires PostHog Flutter SDK 5.34.0+ and posthog-js 1.408.0+). See masking on Flutter Web under the Flutter tab.
Surveys
Note: Surveys are supported in Flutter for Web, iOS, and Android platforms.
Surveys launched with popover presentation are automatically shown to users matching the display conditions you set up.
Push notifications
The Flutter SDK can register a device for Workflows push notifications and capture when a user opens one. For setup, including automatic and manual registration, capturing opens, opting out, and identity verification, see Push notifications.
Flush
import FlushIntro from '../_snippets/flush-intro.mdx'
You can also configure the flush interval with flushInterval (default 30 seconds), after which queued events are sent regardless of how many have been gathered:
final config = PostHogConfig('<ph_project_token>'); config.flushAt = 20; config.flushInterval = const Duration(seconds: 30);
import FlushManual from '../_snippets/flush-manual.mdx'
await Posthog().flush();
import FlushNotes from '../_snippets/flush-notes.mdx'
Offline behavior
The PostHog Flutter SDK will continue to capture events when the device is offline for Android and Apple platforms. The events are stored in a queue in the device's file storage and are flushed when the device is online.
- The queue has a maximum size defined by
maxQueueSizein the configuration. - When the queue is full, the oldest event is deleted first.
- The queue is flushed when the app is restarted and the device is online.
Opt out of data capture
You can disable data collection for a user at any time using the disable() method:
await Posthog().disable();
This prevents any future events from being sent. It doesn't remove events already captured for the user. To opt the user back in:
await Posthog().enable();
To check if a user is opted out:
await Posthog().isOptOut();
Amending or dropping events
Since version 5.13.0, you can provide beforeSend callbacks when initializing the SDK to amend or drop events before they are sent to PostHog.
Redacting information in events
beforeSend gives you one place to edit or redact information before it is sent to PostHog. For example:
final config = PostHogConfig('<ph_project_token>'); config.host = '<ph_client_api_host>'; config.beforeSend = [ (event) { // Redact email from properties if (event.properties?['email'] != null) { event.properties?['email'] = '***@***.***'; } return event; }, ]; await Posthog().setup(config);
Dropping events
Return null from the callback to drop the event:
config.beforeSend = [ (event) { // Drop events you don't want to send if (event.event == 'ignored_event') { return null; } return event; }, ];
Filtering autocaptured screens
import FilterScreenEvents from '../_snippets/filter-screen-events-beforesend.mdx'
const ignoredScreens = {'Splash', 'Debug'}; config.beforeSend = [ (event) { final screenName = event.properties?['$screen_name']; if (event.event == '$screen' && ignoredScreens.contains(screenName)) { return null; } return event; }, ];
Limitations
The beforeSend callbacks only apply to events captured via Dart APIs:
Posthog().capture()- custom eventsPosthog().screen()- screen events (event name is$screen)Posthog().captureException()- exception events (event name is$exception)
They do not intercept native-initiated events such as:
- Session replay events (
$snapshot) - Application lifecycle events (
Application Opened, etc.)
Additionally, only user-provided properties are available in the callback. System properties (like $device_type, $session_id) are added by the native SDK at a later stage.
Debug mode
If you're not seeing the expected events being captured, the feature flags being evaluated, or the surveys being shown, you can enable debug mode to see what's happening.
You can enable debug mode during initialization by setting the debug option to true in the PostHogConfig object. A common pattern is to set this to true in development environments only using environment variables.
final config = PostHogConfig('<ph_project_token>'); config.host = '<ph_client_api_host>'; config.debug = true; // + await Posthog().setup(config);
This will enable verbose logs about the inner workings of the SDK.
You can also enable debug by calling the Posthog().debug() method in your code.
await Posthog().debug(true); await Posthog().debug(false);