On this page

For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.

Flutter Session Replay

Flutter Session Replay records application sessions on iOS and Android. Connect replays to your Amplitude events by sharing device and session IDs. Use add-to-app when an iOS or Android host app manages recording.

Use the current stable release, 1.0.0, of the amplitude_session_replay package. If you're upgrading from a beta, refer to Upgrade from earlier beta versions.

You need your Amplitude project's API key to initialize Flutter Session Replay. You must also set a device ID and an active session ID. To link replays with analytics events, use the same top-level device_id and session_id values. Follow Connect Session Replay to use the IDs from Analytics Flutter.

Keep these IDs synchronized when your application starts a new session or changes identity. To report issues, contact Amplitude support.

Compatibility

Widgets that use RSuperellipse require Flutter 3.32 or later. Flutter-only recording captures the primary Flutter view; for multiple-engine host applications, follow Add-to-app.

Quickstart

Configure your Amplitude project

In Session Replay settings, enable session capture for your project and set its sampling rate. Configure its masking level using Manage privacy settings.

By default, Flutter Session Replay reads sampling and masking settings from the Amplitude project identified by your apiKey. Set that project's sampling rate above 0% before starting recording.

Install and initialize

Add Flutter Session Replay to your pubspec.yaml:

yaml
dependencies:
  amplitude_session_replay: ^1.0.0

Then run flutter pub get.

SessionReplay is a process-wide singleton. Access it through SessionReplay.instance, and don't construct it directly.

Configure your application code:

  1. Call SessionReplay.instance.init() with a SessionReplayConfig, passing your API key, device ID, and session ID. init() is synchronous.
  2. Call start() to request recording.
  3. When the session ID or device ID changes, call setSessionId() or setDeviceId() to keep Session Replay synchronized.

Analytics identifiers

The examples use an initialized Analytics Flutter client named analytics. Read its device and session IDs before configuring Replay. Later configuration examples reuse the validated deviceId and sessionId from this setup. If you use another analytics provider, supply that provider's matching IDs.

dart
import 'package:amplitude_flutter/amplitude.dart';
import 'package:amplitude_session_replay/amplitude_session_replay.dart';

Future<void> startReplay(Amplitude analytics) async {
  await analytics.isBuilt;
  final deviceId = await analytics.getDeviceId();
  final sessionId = await analytics.getSessionId();
  if (deviceId == null || sessionId == null || sessionId <= 0) return;

  SessionReplay.instance.init(
    SessionReplayConfig(
      apiKey: 'YOUR_AMPLITUDE_API_KEY',
      deviceId: deviceId,
      sessionId: sessionId,
      privacyConfig: PrivacyConfig.conservative,
    ),
  );
  await SessionReplay.instance.start();
}

Debug recording

Debug sessions only

For local debugging, disable remote configuration and set sampleRate: 1.0 to select every test session. Use the same development project for Analytics and Replay, and keep the required masking level.

Supply a production configuration with the same project API key, server zone, and current device and session IDs as the Analytics client.

dart
import 'package:amplitude_session_replay/amplitude_session_replay.dart';
import 'package:flutter/foundation.dart';

Future<void> startReplayForBuild(
  SessionReplayConfig productionConfig,
) async {
  final config = kDebugMode
      ? SessionReplayConfig(
          apiKey: 'YOUR_DEVELOPMENT_AMPLITUDE_API_KEY',
          deviceId: productionConfig.deviceId,
          sessionId: productionConfig.sessionId,
          enableRemoteConfig: false,
          sampleRate: 1.0,
          privacyConfig: PrivacyConfig.conservative,
        )
      : productionConfig;

  SessionReplay.instance.init(config);
  await SessionReplay.instance.start();
}

Connect Session Replay

To link replays with analytics events, use the same project API key, server zone, device ID, and session ID for both SDKs. Refer to Session matching.

Use the current Analytics Flutter SDK and read its session ID and device ID with getSessionId() and getDeviceId(). Update Replay's IDs when Analytics changes them. Stop recording during identity changes and resume after the IDs match. Apply consent changes to both SDKs.

For applications that embed Flutter in an iOS or Android host, follow Add-to-app.

Configuration

Pass the following options through SessionReplayConfig when you call SessionReplay.instance.init():

Remote configuration

With enableRemoteConfig: true, the project's remote settings take precedence over local sampling and privacy settings. Manage those settings in Session Replay settings.

The default local privacy level is PrivacyConfig.medium. Set the required privacyConfig before starting recording, and use privacy wrappers for sensitive content. Local masking applies until the project's remote privacy setting arrives, so the local level must protect content from the start.

For local testing, follow Debug recording.

Mask onscreen data

Session Replay provides three Flutter widgets for privacy control. These widgets apply to the entire subtree of the wrapped widget. Priority order: AmpBlock > AmpMask > AmpUnmask.

Privacy levels

The privacyConfig option controls automatic masking behavior:

AmpMask

Masks Flutter text with a rectangle matching the text bounds. Use AmpMask for sensitive text that the automatic privacy level doesn't cover:

dart
AmpMask(
  child: Text('Sensitive information'),
)

Images don't receive automatic masking at any privacy level. Wrap sensitive images or image-containing subtrees in AmpBlock. AmpMask doesn't hide image content.

AmpBlock

Blocks an entire subtree from recording and replaces it with a placeholder. Use this for highly sensitive content:

dart
AmpBlock(
  child: TextField(
    decoration: InputDecoration(labelText: 'Password'),
  ),
)

AmpUnmask

Prevents automatic masking from privacy level rules. Use this to reveal content that the privacy level would otherwise mask. AmpUnmask can't override a manual AmpMask or AmpBlock:

dart
AmpUnmask(
  child: Text('Public content'),
)

Platform views

Supported embedded platform views are blocked by default, including views without a Flutter privacy wrapper. Register the plugin before creating these views. The application UI stays visible. Use AmpUnmask only when the platform view and every descendant are safe to record. Wrapper precedence remains AmpBlock > AmpMask > AmpUnmask.

To record maps, use Android Google Maps or iOS MapKit and wrap the view in AmpUnmask.

Keep sensitive platform views blocked from creation. Later masking can retain previously captured pixels. On Android, keep sensitive WebViews blocked rather than switching them to AmpMask after recording begins.

Platform views can appear above Flutter overlays in a replay. For installation requirements, refer to Plugin registration.

User opt-out

To opt users out of session replay collection, pass optOut: true during initialization, or call setOptOut(optOut: true) at runtime. Apply consent changes to both Replay and your analytics SDK. Stop capture before displaying restricted content.

dart
await SessionReplay.instance.setOptOut(optOut: true);

EU data residency

Amplitude customers who use the EU data center can access Session Replay. Set serverZone to ServerZone.eu during initialization.

dart
SessionReplay.instance.init(
  SessionReplayConfig(
    apiKey: 'YOUR_AMPLITUDE_API_KEY',
    deviceId: deviceId,
    sessionId: sessionId,
    serverZone: ServerZone.eu,
  ),
);

Sampling rate

Set the project's sampling rate in Session Replay settings. Remote configuration is enabled by default and takes precedence over the local sampleRate.

For local testing, follow Debug recording to disable remote configuration and select every test session.

Update the session ID

When Analytics starts a new session, read its current session ID and pass it to Flutter Session Replay. In this example, analytics is your initialized Analytics Flutter client:

dart
final sessionId = await analytics.getSessionId();
if (sessionId != null && sessionId > 0) {
  await SessionReplay.instance.setSessionId(sessionId);
}

If your application manages session IDs, pass the same updated ID to Replay and your analytics events. Refer to Connect Session Replay for identity and session synchronization.

Start and stop recording

Control recording for specific pages or features:

dart
// Stop recording before entering a restricted area
await SessionReplay.instance.stop();

// Resume recording after leaving the restricted area
await SessionReplay.instance.start();

Disable replay collection

After you enable Session Replay, it runs on your app until either:

  • The user leaves your app.
  • You call SessionReplay.instance.stop().
  • You call SessionReplay.instance.dispose().

Call SessionReplay.instance.stop() before a user navigates to a restricted area of your app to disable replay collection while the user is in that area.

Call SessionReplay.instance.start() to re-enable replay collection when the user returns to an unrestricted area of your app.

Add-to-app

If your Flutter module runs inside an iOS or Android host app that already records Session Replay, call SessionReplay.instance.attach() instead of init(). Configure the API key, device ID, session ID, sampling, masking, and recording lifecycle in the host app.

dart
import 'package:amplitude_session_replay/amplitude_session_replay.dart';
import 'package:flutter/widgets.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // Connect Flutter to the host app's Session Replay recording.
  SessionReplay.instance.attach();

  runApp(const MyApp());
}

In add-to-app integrations, configure recording through the host app. Dart start(), stop(), flush(), setOptOut(), setSessionId(), and setDeviceId() have no effect. Dart dispose() disconnects Flutter without stopping the host's recording.

If your app runs multiple Flutter engines, call attach() in each entry point.

Plugin registration

Automatic Flutter plugin registration handles this setup for standard Flutter applications. For manual registration or add-to-app integrations, register AmplitudeSessionReplayPlugin with every Flutter engine before creating platform views and before recording starts.

In add-to-app integrations, call attach() in each Flutter entry point in addition to registering the plugin. Registering after view creation can leave those views unblocked. In add-to-app integrations, check the plugin's isNativeViewBlockingAvailable property before the host starts recording.

Methods

Call these methods on the SessionReplay.instance singleton:

Lifecycle

Flutter Session Replay lifecycle: init(config) creates the Initialized state, start() moves to Started, stop() moves to Stopped, start() returns Stopped to Started, dispose() from any state moves to Disposed, and init(config) revives Disposed back to Initialized. Flutter Session Replay lifecycle: init(config) creates the Initialized state, start() moves to Started, stop() moves to Stopped, start() returns Stopped to Started, dispose() from any state moves to Disposed, and init(config) revives Disposed back to Initialized.

init() is one-shot per lifecycle: it's only callable from the uninitialized (or disposed) state. To re-initialize with a new config, call dispose() first, then init() again.

You can call dispose() from any state. It returns the singleton to its uninitialized state, so a later init() or attach() cleanly revives it. Use dispose() for permanent teardown only. To temporarily pause and resume recording, use stop() and start() instead.

Upgrade from earlier beta versions

Version 0.1.0-beta.5 introduced the singleton API. SessionReplay is a process-wide singleton, and installation no longer requires the SessionReplayWidget wrapper.

Experimental configuration options have changed. If your integration uses experimental options, contact Amplitude support for help migrating.

Breaking changes

For Flutter-only apps:

For add-to-app:

Flutter-only apps

Replace the constructor and SessionReplayWidget wrapper with SessionReplay.instance.init() and start():

dart
// Before
final sessionReplay = SessionReplay(
  SessionReplayConfig(apiKey: '...', sampleRate: 1.0),
);
runApp(SessionReplayWidget(sessionReplay: sessionReplay, app: const MyApp()));
await sessionReplay.start();

// After
SessionReplay.instance.init(          // synchronous, no await
  SessionReplayConfig(
    apiKey: 'YOUR_AMPLITUDE_API_KEY',
    deviceId: deviceId,
    sessionId: sessionId,
  ),
);
await SessionReplay.instance.start();
runApp(const MyApp());                // no SessionReplayWidget wrapping needed
  • init() is one-shot per lifecycle. Call await SessionReplay.instance.dispose() before re-initializing with a new config.
  • Setters (setSessionId(), setDeviceId(), setOptOut()) still work between init() and start().

Add-to-app

Replace the placeholder config and widget wrapper with a single attach() call:

dart
// Before: placeholder config and widget wrapper
return SessionReplayWidget(
  sessionReplay: SessionReplay(
    const SessionReplayConfig(
      apiKey: 'YOUR_API_KEY',
      deviceId: 'YOUR_DEVICE_ID',
      shouldInitializeNativeSDK: false,
    ),
  ),
  app: MaterialApp(...),
);

// After: one line per entry point, no config needed
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SessionReplay.instance.attach(); // host manages config and lifecycle
  runApp(const MyApp());
}
  • Call attach() in every Dart entry point.
  • Remove conflicting dependency version pins in the host app so the Flutter package can install its required dependencies.

Session Replay properties

Remove all calls to sessionReplayProperties(). Amplitude matches replays to analytics events by deviceId and sessionId. Make sure those match the identifiers you send with your analytics events. For more information, refer to Session matching.

The AmpMask, AmpUnmask, and AmpBlock privacy widgets are unchanged.

Data retention, deletion, and privacy

Review consent guidance when you implement capture.

Retention period

For native and Flutter SDK retention guidance and the effective date of changes, go to the Session Replay data lifecycle reference.

DSAR API

For replay metadata returned by the DSAR API, go to Session Replay DSAR metadata.

Data deletion

For user and project deletion behavior, go to Session Replay data deletion.

Bot filter

For bot filtering and property-filter restrictions, go to Session Replay bot filtering.

Troubleshooting

Session replays don't appear in Amplitude

Session replays may not appear because of:

  • Lack of network connectivity.
  • Sampling excluded the session (sampleRate too low).
  • No events sent with matching deviceId and sessionId for the session.
  • A missing SessionReplay.instance.start() call after init().

Verify your configuration

  1. Check that your project sampling rate is greater than 0%. If you disabled remote configuration, set the local sampleRate above 0.0.
  2. Confirm you call SessionReplay.instance.start() after SessionReplay.instance.init().
  3. Ensure the apiKey, deviceId, and sessionId match the values you send with analytics events.

Verify network connectivity

Ensure your app has access to the internet and try again.

Check sample rate

When remote configuration is enabled, check the sampling rate in Session Replay settings. For local configuration, set sampleRate above its 0.0 default. Refer to Sampling rate.

Session Replay processing errors

Replays appear in Amplitude within minutes of ingestion. Delays or errors may result from:

  • Mismatched API keys or device IDs between Session Replay and your analytics instrumentation.
  • Session Replay references the wrong project.
  • Short sessions. If a user bounces within a few seconds of initialization, the SDK may not have time to upload replay data.

Platform view blocking is unavailable

If recording stops with NATIVE_VIEW_BLOCKING_UNAVAILABLE, check that AmplitudeSessionReplayPlugin registers with every engine before platform-view creation. Confirm your Flutter version meets the compatibility requirements and remove conflicting dependency version pins.

Keep recording disabled until blocking is available. If the issue continues, contact Amplitude support with your Flutter version and logs. In add-to-app integrations, check the plugin's isNativeViewBlockingAvailable property before the host starts recording.

Flush returns but no replay appears

Call flush() after start() to request upload of pending replay data. Check logs, connectivity, sampling, and matching analytics events if the replay doesn't appear. In add-to-app integrations, request the upload through the host app.

Was this helpful?