Fullstory for Flutter Mobile Apps provides two levels of data capture for your Flutter apps: basic data capture and session replay, both of which are generally available. Data from your Flutter apps can be combined in Fullstory with sessions from your website and other mobile apps to provide a comprehensive view of your digital experience.
This article will cover the following:
Setting up your Flutter app
Setting up Fullstory for your Flutter app is a two-step process. First, you install and configure the fullstory_flutter library to enable basic data capture. Then, you enable session replay to add visual capture of your Flutter UI.
Prerequisites: Update to Flutter 3.32 or higher before beginning setup.
Step 1: Set up basic data capture
Basic data capture allows you to capture user events and important details about their sessions to better understand your users' experience with your app. This data can be used to analyze key metrics, understand user journeys, and identify drop-off points in your most important user funnels.
See Fullstory for Flutter Mobile Apps - API Overview for a list of all supported API methods for Flutter. In addition to the data captured via those API methods, Fullstory automatically captures the following for Flutter apps:
- Session metadata (e.g. device details, OS, location, app version, etc.)
- Navigate events at top-level FlutterViewController/FlutterActivity
- Network and Console capture
- Visual capture of parts of the app built via a native mobile framework
Follow the instructions below to install and configure fullstory_flutter via pub.dev.
-
Install the
fullstory_flutterDart library by running the following command in the root directory of your Flutter app:flutter pub add fullstory_flutter
This also installs the Fullstory CocoaPod for iOS apps. The Android library requires separate installation.
-
Follow the guides below to configure this for your Android or iOS app.
-
Android Apps: Install and configure the Android library by following Getting Started with Android Data Capture.
Note: Follow Step 5 for Android (Subclass from Application), as the default Flutter setup does not work. Ensure the Android SDK version in
pubspec.yamlmatches the Flutter version—for example, if Flutter is 0.70.1, Android should be 1.70.1. - iOS Apps: Configure iOS starting from Step 1: Adding the Fullstory framework via CocoaPods Pod > Add the Build Phase in Getting Started with iOS Data Capture. In Step 1, skip the Add the Plugin step found under the via CocoaPods Pod instructions and begin immediately with the Add the Build Phase instructions.
Note: If you add your Flutter code to an existing Android or iOS app as an add-to-app module, follow the directions above, applying Android and iOS steps to your native apps, not the Flutter module. When building the Flutter module for Android, you may need the following additional options when running
flutter build aar(note: Flutter's-Pflag requires a space, unlike Gradle's):-P shrink=falseis needed if you get the errorExecution failed for task ':flutter:minifyReleaseWithR8'—this option skips the minification phase for release builds, which is currently broken for plugins like Fullstory's.-P fsTarget=1.56.0(or your installed version) is needed if you encounter errors due to a version mismatch between your Android and Flutter Fullstory plugins. -
-
Import the library into your Dart code and begin using the API. The following is a non-exhaustive reference showing several common API methods; for the complete API, see the Fullstory for Flutter Mobile Apps - API Overview.
// Upon user login // The second parameter is optional and can be updated later by calling FS.setUserVars() FS.identify('462718483', { 'displayName': 'Daniel Falko', 'email': 'daniel.falko@example.com', }); // Update user details // Arbitrary keys and values are allowed // displayName and email get special treatment by Fullstory FS.setUserVars({ 'displayName': 'Daniel Falko', 'email': 'daniel.falko@example.com', 'membershipLevel': 'platinum', }); // Upon user log out FS.anonymize(); // Create custom events FS.event('new thing created'); // ...with optional properties FS.event('new thing created', {'name': 'foo', 'value': 2.5}); // Get the Fullstory session URL // Will be null if there is no current session, see FSStatusListener FS.getCurrentSessionURL().then((url) = print("Fullstory session url: $url")); // Log messages // Logs will appear in Dev tools > Console section of Fullstory playback // Errors will also appear in the event list at the right // Supported log levels are: log, debug, info, warn, error FS.log(level: FSLogLevel.error, message:"Exception caught: $e"); // Get notified when the Fullstory session has started // (The mixin can also be added to existing classes and widgets) class MyStatusListener with FSStatusListener { MyStatusListener() { FS.setStatusListener(this); } @override void onFSSession(String url) { print("Fullstory session started: $url"); } } var listener = new MyStatusListener(); - Before progressing further, build your app to make sure things still work as expected.
Note: For more information on Mobile APIs, see the developer documentation. You can also refer to the Fullstory Flutter GitHub repository for working examples of the API.
Checkpoint: At this point, your app is set up for basic data capture. Build your app and verify that sessions appear in Fullstory. When you are ready to add visual capture of your Flutter UI, continue to Step 2.
Step 2: Enable session replay
Session replay provides privacy-first visual wireframe capture of your Flutter UI, allowing you to see exactly what your users see. Once you have basic data capture set up and your app is building as expected, complete the following steps to enable session replay:
- In your app's
main.dart(or wherever the app is started):- Add
import 'package:fullstory_flutter/fullstory_flutter.dart';. - Replace
runApp($YourAppHere$)withrunFullstoryApp($YourAppHere$). - If you use
runWidget, replace it withrunFullstoryWidget. Please contact us if you encounter issues withrunFullstoryWidget.
- Add
- If you use
WidgetsFlutterBinding.ensureInitialized(), replace it withFullstoryBinding.ensureInitialized(). - Run the app again and ensure that a session is successfully captured.
Additional configuration
See the sections below for additional configuration options.
Custom classes and attributes
Use FSCustomAttributes to add custom classes or attributes to your widgets. Wrap the widget you want to annotate with FSCustomAttributes and add any classes or attributes you wish to include.
Example usage:
FSCustomAttributes (
classes: ['class1', 'class2'],
attributes: {'field1': 'value1'},
child: YourWidget(),
)WebView support
Some packages, such as WebView for Flutter, require additional configuration to enable WebView support in session replay. Other packages, such as InAppWebView, do not have this requirement by default.
Flutter disables JavaScript injection on all WebViews it creates by default. To allow Fullstory to include Flutter WebViews in session replay, call the following on each WebViewController you want to capture:
controller.setJavaScriptMode(JavaScriptMode.unrestricted)
Additional data capture options
To enable additional data capture options, such as pages and network requests, see the Fullstory for Flutter developer documentation.
Capturing images
Image and icon capture is available as an opt-in feature in Fullstory for Flutter. To enable it, pass captureImages: true to runFullstoryApp():
runFullstoryApp(YourApp(), captureImages: true);
Note: Image capture is currently opt-in and is expected to become enabled by default in a future release.
Logging
Note: The logLevel parameter on runFullstoryApp() is deprecated as of Fullstory Flutter SDK 1.72.0.
Log level is now configured via the native platform configuration:
-
Android: Set the
logLevelproperty in thefullstoryblock of yourbuild.gradlefile. See Android Configuration. -
iOS: Set the
LogLevelkey in theFullstorydictionary in yourInfo.plistfile. See iOS Configuration.
Obfuscation support
If you use --obfuscate to obfuscate your release app, follow these steps to see unobfuscated selectors in replay. This is necessary for Unmasking to work.
Note: These steps bundle deobfuscation mapping for public class names into app binaries. No variables, fields, methods, or any private symbols are included.
On Android, the Fullstory Gradle plugin picks up the mapping file automatically, so only step 2 below is required. On iOS, you must also complete step 1 so the Fullstory iOS SDK knows where to find the mapping file.
-
iOS only: Before building, set an environment variable so the Fullstory iOS SDK can find the mapping file:
export FS_FLUTTER_OBFUSCATION_MAP=/path/to/file.json
Note: The path must be an absolute path, not a relative path.
-
Android and iOS: When building, pass the following additional flag to save the obfuscation map:
--extra-gen-snapshot-options=--save-obfuscation-map=/path/to/file.json
Disable obfuscation support
To disable obfuscation support, use the following build-time configuration:
-
Android: Pass
-P flutterSelectorDeobfuscationEnabled=false. -
iOS: Do not set
FS_FLUTTER_OBFUSCATION_MAP.
Note: Disabling obfuscation support will typically result in fully masked playback and disable Fullcapture.
Limitations and Known Issues
Fullstory's Flutter support provides privacy-first visual wireframe replay. Developers should be aware of the following limitations and known issues.
Limitations
Note the following limitations for Fullstory Flutter features:
- Image and icon capture is available as an opt-in feature via the
captureImagesparameter onrunFullstoryApp(); see Capturing images. It is expected to become enabled by default in a future release. - Watched elements are not supported.
Known Issues
Fullstory's Flutter support has the following known issues:
- Not compatible with tools and frameworks like Patrol which also use custom bindings. Please contact us to determine a way to combine our binding with your framework's.
- Apps which have multiple FlutterViews on screen at the same time aren't supported yet. Please contact us if you use multiple FlutterViews.
- Flutter views cannot be unmasked using selectors for native views. Use a
RootWidgetor similar instead. - Flutter Web is not supported.
- The Flutter SDK may emit a warning about lack of built-in Kotlin support for Flutter apps built with Flutter versions earlier than 3.44. This warning is expected and will be resolved in a future Fullstory release.