Flutter Session Replay installation

Contents

  1. Install the package

    Required

    Add the PostHog Flutter SDK to your pubspec.yaml:

    pubspec.yaml
    posthog_flutter: ^5.24.0
    SDK version

    Session replay requires PostHog Flutter SDK version 4.7.0 or higher. We recommend always using the latest version.

  2. Disable auto-init for Android

    Required

    For session replay, you need to use manual initialization. Add this to your AndroidManifest.xml to disable auto-init:

    android/app/src/main/AndroidManifest.xml
    <application>
    <activity>
    [...]
    </activity>
    <meta-data android:name="com.posthog.posthog.AUTO_INIT" android:value="false" />
    </application>

    Update the minimum Android SDK version to 21 in android/app/build.gradle:

    android/app/build.gradle
    defaultConfig {
    minSdkVersion 23
    // rest of your config
    }
  3. Disable auto-init for iOS

    Required

    Add this to your Info.plist to disable auto-init:

    ios/Runner/Info.plist
    <dict>
    [...]
    <key>com.posthog.posthog.AUTO_INIT</key>
    <false/>
    [...]
    </dict>

    Update the minimum platform version to iOS 13.0 in your Podfile:

    Podfile
    platform :ios, '13.0'
    # rest of your config
  4. Enable session recordings in project settings

    Required

    Go to your PostHog Project Settings and enable Record user sessions. Session recordings will not work without this setting enabled.

    If you're using Flutter Web, also enable the Canvas capture setting. This is required as Flutter renders your app using a browser canvas element.

  5. Initialize PostHog with session replay

    Required

    Initialize PostHog in your main.dart with session replay enabled. Here are all the available options:

    main.dart
    import 'package:flutter/material.dart';
    import 'package:posthog_flutter/posthog_flutter.dart';
    Future<void> main() async {
    WidgetsFlutterBinding.ensureInitialized();
    final config = PostHogConfig('<ph_project_token>');
    config.host = 'https://us.i.posthog.com';
    config.debug = true;
    config.captureApplicationLifecycleEvents = true;
    // Enable session recording. Requires enabling in your project settings as well.
    // Default is false.
    config.sessionReplay = true;
    // Enable masking of all text and text input fields. Default is true.
    config.sessionReplayConfig.maskAllTexts = false;
    // Enable masking of all images. Default is true.
    config.sessionReplayConfig.maskAllImages = false;
    // Throttling delay used to reduce the number of snapshots captured. Default is 1s.
    config.sessionReplayConfig.throttleDelay = const Duration(milliseconds: 1000);
    await Posthog().setup(config);
    runApp(MyApp());
    }

    For more configuration options, see the Flutter session replay docs.

  6. Wrap your app with PostHogWidget

    Required

    For Session Replay to work, wrap your app with PostHogWidget and add the PosthogObserver:

    MyApp.dart
    import 'package:flutter/material.dart';
    import 'package:posthog_flutter/posthog_flutter.dart';
    class MyApp extends StatelessWidget {
    Widget build(BuildContext context) {
    return PostHogWidget(
    child: MaterialApp(
    navigatorObservers: [PosthogObserver()],
    title: 'My App',
    home: const HomeScreen(),
    ),
    );
    }
    }
  7. Watch session recordings

    Recommended

    Visit your site or app and interact with it for at least 10 seconds to generate a recording. Navigate between pages, click buttons, and fill out forms to capture meaningful interactions.

    Watch your first recording →

  8. Next steps

    Recommended

    Now that you're recording sessions, continue with the resources below to learn what else Session Replay enables within the PostHog platform.

    ResourceDescription
    Watching recordingsHow to find and watch session recordings
    Privacy controlsHow to mask sensitive data in recordings
    Network recordingHow to capture network requests in recordings
    Console log recordingHow to capture console logs in recordings
    More tutorialsOther real-world examples and use cases

Control recording programmatically

Requires PostHog Flutter SDK version >= 5.14.0. Available on iOS, Android, and Web.

Setting config.sessionReplay = false in your PostHog configuration will prevent PostHog from automatically starting session recordings on SDK setup.

You can manually control when to start and stop session recordings using the following methods:

  • startSessionRecording({bool resumeCurrent = true})
    • Set resumeCurrent to true to resume a previous session recording (default).
    • Set resumeCurrent to false to start a new session recording.
    • To begin a completely fresh session, call stopSessionRecording() first, then startSessionRecording(resumeCurrent: false).
  • stopSessionRecording()
    • Stops/pauses the current session recording.
  • isSessionReplayActive()
    • Returns a Future<bool> telling you whether a recording is currently active on this device. Resolves to false when session replay is off, hasn't started yet, or isn't supported on the current platform.

Note: Calling these methods will have no effect if session recordings are disabled in your PostHog Project Settings. Manual starts still respect project ingestion controls, including sampling and event triggers.

Pause recording on a sensitive screen

Masking hides what's drawn on screen, but the recording still includes where each touch lands. On a PIN, passcode, or card-number keypad, the tap positions alone can reveal the value entered, so stop recording while the screen is shown and resume it once the screen is dismissed:

Dart
class PinEntryScreen extends StatefulWidget {
const PinEntryScreen({super.key});
State<PinEntryScreen> createState() => _PinEntryScreenState();
}
class _PinEntryScreenState extends State<PinEntryScreen> {
bool _wasRecording = false;
void initState() {
super.initState();
// Asked before the stop is sent, so it reports the state on entry.
Posthog().isSessionReplayActive().then((active) => _wasRecording = active);
Posthog().stopSessionRecording();
}
void dispose() {
if (_wasRecording) {
Posthog().startSessionRecording();
}
super.dispose();
}
Widget build(BuildContext context) {
return const PinKeypad();
}
}

startSessionRecording() resumes the current session by default, so the replay continues as one recording with the keypad left out. The isSessionReplayActive() check matters: on iOS, startSessionRecording() installs the replay integration if it isn't there yet, so an app that wasn't recording would start when the screen closes. Only resuming when the screen found recording active keeps that from happening.

If you want taps left out of every recording rather than one screen's, set sessionReplayConfig.captureTouches = false before setup() instead (SDK >= 5.41.0); see privacy controls.

Record or ignore specific screens

You can combine these methods with your navigation to record only certain screens, or to pause recording on sensitive ones. For example, using a NavigatorObserver, stop recording on a sensitive route and resume otherwise:

Dart
const ignoredScreens = {'Payment', 'Settings'};
class RecordingByScreenObserver extends NavigatorObserver {
void _update(Route<dynamic>? route) {
final screenName = route?.settings.name;
if (screenName != null && ignoredScreens.contains(screenName)) {
Posthog().stopSessionRecording();
} else {
Posthog().startSessionRecording();
}
}
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) => _update(route);
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) => _update(previousRoute);
}
// Then register it on your MaterialApp:
// navigatorObservers: [RecordingByScreenObserver()]

Invert the check (startSessionRecording only for screens in an allowlist, stopSessionRecording otherwise) if you'd rather record just a specific set of screens.

Still have questions?

Was this page useful?