> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lucenthq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flutter support reference

> Reference for lucent_flutter configuration, replay behavior, persistence, and known limitations.

Use this page when you need the exact Flutter SDK behavior and option surface.
For setup instructions, start with the [Flutter SDK guide](/sdk/flutter).

## Support matrix

| Area | Flutter SDK behavior |
| - | - |
| Package | `lucent_flutter` |
| Supported platforms | iOS and Android |
| Deferred platforms | Flutter Web and macOS are not in the MVP |
| Replay mode | Screenshot-mode mobile replay |
| Backend classification | `lucent-flutter` maps to `mobile_flutter` |
| iOS packaging | CocoaPods is verified |
| Android packaging | Flutter plugin with Android min SDK `23`; release apps need `android.permission.INTERNET` |
| Example app | `sdk-flutter-lucent/example` in the SDK repo |

## Replay envelope

Flutter replay is always sent as mobile screenshot replay:

```json theme={null}
{
  "snapshotSource": "mobile",
  "snapshotLibrary": "lucent-flutter",
  "snapshotMode": "screenshot"
}
```

The SDK captures a masked `RepaintBoundary` image from `LucentWidget`, encodes
it as a mobile screenshot wireframe, and posts batches to `/api/sdk/replay`.
The backend classifies these sessions as `mobile_flutter`.

## Persistence and retry

Replay batches are persisted on disk before upload on iOS and Android. Failed
uploads remain queued for retry.

| Limit | Value |
| - | - |
| Maximum queued batch files | `100` |
| Maximum queued bytes | `50 MB` |
| Maximum queued age | `7 days` |

Android also persists current in-memory replay events between flushes, so
active events can survive a process restart before they become an upload batch.

`flush()` is best effort. If the network request fails, the persisted batch
stays queued and is retried later.

When `LucentWidget` sees the app pause or become inactive, it emits
`Application Backgrounded` and requests a flush. When the app resumes, it emits
`Application Became Active`.

## Configuration

Pass `LucentConfig` to `Lucent().setup(...)`.

```dart theme={null}
await Lucent().setup(
  const LucentConfig(
    publicKey: 'luc_pk_...',
    ingestBaseUrl: 'https://ingest-api.lucenthq.com',
    environment: LucentEnvironment.production,
    autoStart: true,
    remoteConfig: true,
    sessionReplaySampleRate: 1,
    privacy: LucentPrivacyConfig(
      maskAllText: true,
      maskAllImages: true,
    ),
    capture: LucentCaptureConfig(
      touches: true,
      appLifecycle: true,
      errors: true,
      unhandledRejections: true,
      nativeCrashes: true,
      logs: true,
      network: true,
    ),
    batching: LucentBatchingConfig(
      flushInterval: Duration(seconds: 10),
      maxEventsPerBatch: 500,
      maxBatchBytes: 1048576,
    ),
    replay: LucentReplayConfig(
      minimumDuration: Duration.zero,
      screenshotThrottle: Duration(seconds: 1),
      screenshotBackgroundCapture: false,
      eventTriggers: [],
    ),
    metadata: LucentMetadataConfig(
      app: 'Acme Mobile',
      namespace: 'com.acme.mobile',
      version: '1.2.3',
      build: '123',
      release: '1.2.3+123',
      properties: {'tier': 'pro'},
    ),
  ),
);
```

### Core

| Option | Default | Notes |
| - | - | - |
| `publicKey` | Required | Your Lucent public key. Safe to expose in client code. |
| `ingestBaseUrl` | `https://ingest-api.lucenthq.com` | Override only for self-hosted or internal testing. |
| `environment` | `LucentEnvironment.production` | Use `staging` or `development` for non-production apps. |
| `autoStart` | `true` | Set to `false` when you need to wait for consent. |
| `remoteConfig` | `true` | Fetches `/api/sdk/init` before auto-starting when enabled. |
| `sessionReplaySampleRate` | `1` | Clamped between `0` and `1`. |

When `remoteConfig` is enabled, native replay waits for `/api/sdk/init` before
auto-starting. If the request fails, the SDK falls back to local config.

Remote config can disable recording, override session sample rate, update
batching limits, change `minimumDuration`, toggle log/network telemetry, and
replace `eventTriggers`.

### Privacy

| Option | Default | Notes |
| - | - | - |
| `privacy.maskAllText` | `true` | Masks `Text`, `RichText`, and editable text widgets by default. |
| `privacy.maskAllImages` | `true` | Masks rendered image widgets by default. |

`LucentMask` forces masking for a subtree. `LucentNoMask` makes its subtree
visible, so keep sensitive widgets outside any `LucentNoMask` region.

<Warning>
  Flutter does not have browser-style CSS selectors. Review any
  `LucentNoMask` subtree carefully before shipping.
</Warning>

### Capture

| Option | Default | Captures |
| - | - | - |
| `capture.touches` | `true` | Pointer-down coordinates and `$touch` events. |
| `capture.appLifecycle` | `true` | `Application Opened`, `Application Became Active`, and `Application Backgrounded`. |
| `capture.errors` | `true` | Flutter framework errors. |
| `capture.unhandledRejections` | `true` | `PlatformDispatcher` async errors. |
| `capture.nativeCrashes` | `true` | Native uncaught exceptions on next launch. |
| `capture.logs` | `true` | `debugPrint`, `print` inside `runZoned`, and manual logs. |
| `capture.network` | `true` | `dart:io` network breadcrumbs inside `runZoned` and manual network breadcrumbs. |

### Batching

| Option | Default | Notes |
| - | - | - |
| `batching.flushInterval` | `10 seconds` | Native flush loop interval. |
| `batching.maxEventsPerBatch` | `500` | Reaching this triggers a flush. |
| `batching.maxBatchBytes` | `1048576` | Reaching this triggers a flush. |

Native code clamps flush interval, event count, and byte limits to bounded
ranges so misconfiguration does not create extremely small or huge batches.

### Replay

| Option | Default | Notes |
| - | - | - |
| `replay.minimumDuration` | `Duration.zero` | Final flushes shorter than this are dropped. |
| `replay.screenshotThrottle` | `1 second` | How often `LucentWidget` attempts a screenshot. |
| `replay.screenshotBackgroundCapture` | `false` | Screenshots stop while the app is backgrounded by default. |
| `replay.eventTriggers` | `[]` | When set, recording starts after one of these events is tracked. |

`snapshotMode` is not configurable. It is always `screenshot`.

### Metadata and properties

| Option | Event property |
| - | - |
| `metadata.app` | `$app_name` |
| `metadata.namespace` | `$app_namespace` |
| `metadata.version` | `$app_version` |
| `metadata.build` | `$app_build` |
| `metadata.release` | `release` |
| `metadata.properties` | Merged into event metadata |

Use `Lucent().setSessionProperties(...)` and `Lucent().setUserProperties(...)`
when values change during a session.

The native payload also includes common mobile context: `userAgent`, `language`,
`snapshotSource`, `snapshotLibrary`, `snapshotMode`, `os`, `deviceType`, and
`environment`.

## Public API

| Method | Use for |
| - | - |
| `Lucent().setup(config)` | Initialize the SDK and native modules. |
| `Lucent().stop()` | Stop native recording, uninstall Dart hooks, and perform a final native flush. |
| `Lucent().track(name, properties?)` | Capture a custom event. |
| `Lucent().identify(user)` | Associate future events with a known user. |
| `Lucent().resetIdentity()` | Clear the known user and generate a new anonymous ID. |
| `Lucent().screen(name, properties?)` | Emit `$screen` and update replay screen context. |
| `Lucent().setSessionProperties(properties)` | Attach session-level properties. |
| `Lucent().setUserProperties(properties)` | Attach user-level properties. |
| `Lucent().captureLog(message, level, properties)` | Capture a manual log breadcrumb. |
| `Lucent().captureNetwork(...)` | Capture a manual network breadcrumb. |
| `Lucent().captureNetworkRequest(...)` | Wrap an async request and capture timing/status. |
| `Lucent().captureException(error, stackTrace?, properties?)` | Capture a handled exception. |
| `Lucent().addExceptionStep(message, properties?)` | Add an exception breadcrumb. |
| `Lucent().startSessionRecording(resumeCurrent: true)` | Resume screenshot replay. |
| `Lucent().stopSessionRecording()` | Pause screenshot replay and final flush. |
| `Lucent().isSessionReplayActive()` | Check whether replay is currently active. |
| `Lucent().flush(finalFlush: false)` | Flush queued events. Set `finalFlush: true` for a final flush. |
| `Lucent().getSessionInfo()` | Read `sessionId`, `windowId`, and recording state. |
| `Lucent().runZoned(body, onError?)` | Capture `print`, async errors, and `dart:io` network inside a zone. |

`getSessionInfo()` returns `sessionId`, `windowId`, and `recordingEnabled`.
Use `runZoned(..., onError: handler)` if your app already has its own
top-level async error handler.

## Navigation reference

`LucentObserver` accepts two optional callbacks:

| Callback | Use for |
| - | - |
| `nameExtractor(RouteSettings settings)` | Convert route settings into a screen name. Defaults to `settings.name`. |
| `routeFilter(Route<dynamic>? route)` | Decide which routes should emit screens. Defaults to `route is PageRoute`. |

For routers that do not expose named `PageRoute`s, call `Lucent().screen(...)`
from your router listener instead.

## Network privacy

Automatic network capture is limited to `dart:io` `HttpClient` traffic created
inside `Lucent().runZoned(...)`. Other HTTP clients need a wrapper or
interceptor that calls `captureNetworkRequest` or `captureNetwork`.

Lucent captures:

| Field | Captured |
| - | - |
| HTTP method | Yes |
| URL origin and path | Yes |
| URL user info, query, and fragment | No |
| Status code | Yes, when available |
| Duration | Yes, when available |
| Transfer size | Yes, when available |
| Request headers | No |
| Response headers | No |
| Request body | No |
| Response body | No |

Because headers and bodies are not captured, there are no per-field masking
rules for them. Sanitize URLs before manual capture if a path segment contains
sensitive data.

## Error and crash behavior

| Error source | Behavior |
| - | - |
| Flutter framework errors | Captured through `FlutterError.onError` when `capture.errors` is enabled. |
| Async platform errors | Captured through `PlatformDispatcher.instance.onError` when `capture.unhandledRejections` is enabled. |
| Handled exceptions | Capture manually with `Lucent().captureException(...)`. |
| Native uncaught exceptions | Stored synchronously and emitted as `$native_crash` on the next launch. |

Native crash delivery is best effort. If the process cannot write the pending
crash payload before termination, there may be no next-launch crash event.

## Parity checklist

| Capability | Flutter SDK | Notes |
| - | - | - |
| iOS replay | Supported | Screenshot-mode mobile replay. |
| Android replay | Supported | Screenshot-mode mobile replay. |
| Flutter Web replay | Deferred | No web/canvas capture path in the MVP. |
| Root replay wrapper | Supported | Use `LucentWidget`. |
| Route tracking | Supported | Use `LucentObserver` or `Lucent().screen(...)`. |
| Custom events | Supported | Use `Lucent().track(...)`. |
| Identify/reset | Supported | Use `LucentUser` and `resetIdentity`. |
| Touch capture | Supported | Pointer-down coordinate events. |
| Privacy defaults | Supported | Text, inputs, and images mask by default. |
| Logs | Supported | `debugPrint`, `print` in `runZoned`, and manual logs. |
| Network breadcrumbs | Supported | `dart:io` in `runZoned` plus manual APIs. |
| Handled errors | Supported | `captureException` and exception steps. |
| Native crashes | Supported | Next-launch `$native_crash`, best effort. |
| Persistent replay queue | Supported | iOS and Android batch queues with bounded retention. |
| Android current-event persistence | Supported | Current events persist between flushes. |
| Remote config | Supported | `/api/sdk/init` when enabled. |
| Event-triggered replay | Supported | `LucentReplayConfig.eventTriggers`. |
| CocoaPods | Supported | Verified iOS packaging path. |
| Swift Package Manager | Deferred | Use CocoaPods for the MVP. |

## Not in the Flutter MVP

These browser or React Native capabilities are not available in
`lucent_flutter` 0.1.0:

| Capability | Status |
| - | - |
| Flutter Web replay | Deferred until a web/canvas capture path exists. |
| CSS selector privacy rules | Not applicable to Flutter widget trees. Use `LucentMask` and `LucentNoMask`. |
| `networkIgnoreUrls` | Not exposed. Sanitize URLs manually before manual capture if needed. |
| Console level filtering | Not exposed. `debugPrint`, zoned `print`, and manual logs use the configured capture toggle. |
| Rage-click and dead-click detection | Browser-only today. Flutter touch capture is coordinate-level. |
| Alias/group APIs | Not in the Flutter MVP. |
| Persistent super-property registry | Not in the Flutter MVP. Use metadata, session properties, and user properties. |
| Source maps or native symbolication | External to the Flutter SDK docs today. |
| Expo/Metro tooling | React Native only. |

## Troubleshooting

| Symptom | Check |
| - | - |
| No replay appears | Confirm `LucentWidget` wraps the app root and `sessionReplaySampleRate` is greater than `0`. |
| No screen names | Add named routes, customize `LucentObserver`, or call `Lucent().screen(...)` manually. |
| `print` logs are missing | Make sure `runApp` runs inside `Lucent().runZoned(...)`. |
| Network calls are missing | Confirm the client uses `dart:io` inside `runZoned`, or add manual/interceptor capture. |
| iOS build fails around pods | Run `flutter pub get`, then `cd ios && pod install`. |
| iOS SPM warnings appear | Use CocoaPods for the MVP; Swift Package Manager support is deferred. |
| A physical iOS device will not run | Enable Developer Mode and trust the development certificate/device pairing. |
| Android release uploads fail | Add `<uses-permission android:name="android.permission.INTERNET" />` to `android/app/src/main/AndroidManifest.xml`. |
| Android device install fails | Confirm USB debugging is enabled and the device trusts the development machine. |
| Replay is too sparse | Lower `replay.screenshotThrottle`, but watch bandwidth and battery use. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.