Browse In-App Agent

Flutter SDK — Release Notes

embed_flutter · release history, newest first. Install the latest with flutter pub add embed_flutter; confirm the current version on pub.dev.


0.4.0

Released: October 2026

0.4.0 brings the Flutter SDK in line with the React Native and Android SDKs. It also makes calls safer, and the SDK now handles its own Android permissions. Flutter and platform minimums are unchanged from 0.3.0. Nothing was removed from the public API. Two things need your attention: call EmbedWidget.clearUserSession() on logout, and check any analytics that read click event names. See the upgrade steps.

Behaviour changes

ChangeWhat to do
The signed-in user is kept across app restarts until logout. 0.3.0 forgot it at every launch, so the agent, its token and events now work from a cold start.Call EmbedWidget.clearUserSession() on logout. Otherwise the next person is treated as the previous user until a new USER_DATA arrives.
Click event names follow the convention shared with Android, React Native and web. event_name is <name>_<suffix> (pressed, toggled, selected, opened) and no longer ends in _<screen>; the screen is in context.screen. The name comes from the control's ValueKey<String>, Semantics(identifier:), tooltip or text, then the image or icon it draws. Every tappable control is tracked, not only Material buttons.Update dashboards that read click names. A keyed Material button also sends its old name as legacy_event_name. Give important controls a ValueKey<String> for a stable name.
Events need a signed-in user. Without one they aren't sent and embedEvent returns false. With one, they go out whatever the widget is doing (hidden, excluded screen, config still loading).Send USER_DATA after login, as before.
embedOnAgent receives the same agent events as React Native. rage_click and screen_view are analytics only and no longer reach it.Use embedOn if you listened for those two on embedOnAgent.
Touching the app stops the agent's on-screen action. A user touch while the agent is acting cancels the action and removes its highlight. Touches on the SDK's own widget don't count.Nothing.
Android permissions come from the SDK. Its manifest declares every permission a call needs, and it asks for Nearby devices (Bluetooth, Android 12+) only when a Bluetooth headset is connected.Nothing. The permissions already in your manifest can stay.

New

  • Pause and resume the agent without ending the call: EmbedWidget.pauseAgent(), resumeAgent() and isAgentPaused (also embedPauseAgent(), embedResumeAgent(), embedIsAgentPaused()). Pausing mutes the mic; resuming turns it back on if it was on.
  • Hide part of a screen from the agent: give it a Semantics identifier starting with embed-redact. Its content is left out of what the agent sees and of click names; the agent can still tap it.
  • More dashboard appearance options:
    • multi-colour gradients with a direction (horizontal, vertical or diagonal);
    • left and top insets;
    • how long the agent's reply card stays open.
  • Dashboard changes appear on the next launch, not the one after.
  • Call status line with rotating phrases, captions that grow and scroll, and screen-reader labels on every control in the widget.

Fixed

  • A network change during a call no longer turns the microphone back on after the user muted it or paused the agent. It also no longer stops the agent's current task or reports the call twice.
  • Bluetooth and wired headsets keep the call audio. The SDK no longer forces the loudspeaker, and connecting or disconnecting a headset follows the user's choice.
  • No hidden live calls. Leaving the screen while a call is connecting cancels it, instead of letting it go live with no End button.
  • A failed connection shows "Couldn't connect — tap to retry" instead of hiding the agent. A failure at sign-in is retried automatically.
  • The call button's border colour now outlines the Start call button, as on Android and React Native.
  • Failed analytics are retried one by one and are no longer merged. Event and session IDs can no longer collide.

Upgrade steps: 0.3.0 → 0.4.0

  1. Update pubspec.yaml to embed_flutter: ^0.4.0 and run flutter pub get.
  2. Call EmbedWidget.clearUserSession() in your logout flow.
  3. If you report on click events, update for the new event_name format. Optionally give key controls a ValueKey<String>.
  4. If you listened for rage_click or screen_view with embedOnAgent, switch to embedOn.
  5. Rebuild and test a call on a real device, including one with a Bluetooth headset.

0.3.0

Released: October 2026

0.3.0 focuses on accuracy. The agent now reports what it actually did: a step counts as succeeded only when the intended control was acted on and the result was seen. The release also gives every screen a stable name that is the same in debug, release and --obfuscate builds, and keeps behaviour in line with the Android SDK and the Revrag backend. No public API was removed or renamed, and upgrading from 0.2.0 needs no code changes. You do need Flutter 3.29 or newer. See the upgrade steps.

New requirements

Requirement0.2.00.3.0
Flutter≥ 3.0.0≥ 3.29.0
Dart≥ 3.0.0≥ 3.7.0
Android / iOS floorsminSdk 21, iOS 13.0unchanged

If your app can't move to Flutter 3.29 yet, pin embed_flutter: 0.2.0.

Behaviour changes

ChangeWhat to do
Only disabledRoutes keeps the agent from looking at a screen. The data-capture setting, a hidden agent button and the enabledRoutes / platform allowlist no longer block an action the agent is running. They control where the button shows and what telemetry is sent.Put every screen the agent must never see (login, OTP, payment, regulated data) in disabledRoutes.
Named dialogs and bottom sheets in disabledRoutes block capture but no longer hide the agent button. The button follows the page underneath. Their open and close analytics are back.Give sensitive dialogs a name: routeSettings: RouteSettings(name: 'otp_dialog'), then list it in disabledRoutes.
Telemetry continues while the button is hidden (for example during a button delay), matching Android. Screens in disabledRoutes are still never covered.Nothing, unless this conflicts with your data policy. Then contact Revrag.
Screen names come from your route names first. Tabs of an IndexedStack / PageView are named route/tab, and an unnamed pushed page with no other signal is named route/page_1, route/page_2, and so on. Class names are never used, so debug, release and obfuscated builds all agree.Name your routes. Give each tab root a ValueKey<String>, or wrap it in EmbedRouteListener. See Stable screen names.
Agent results are stricter. A step that can't be confirmed now fails with a specific reason (target_mismatch, ambiguous_target, verification_unavailable, target_disabled, and others) instead of reporting success. A tap whose only visible effect is elsewhere on the screen, such as a counter or a badge, no longer counts as success.Label icon-only buttons and expose selected / checked on custom tabs, chips and radios. See Troubleshooting.
Element IDs changed, and the on-device screen cache moves to a new format. Old cached screens are discarded locally on first launch and never uploaded.Nothing. The cache rebuilds as users browse.

New

  • Honest results. The SDK never types into a field whose own label names something else (it won't type a "Full Name" into a field labelled "PIN"), and it never guesses between two equally good matches. Before tapping, typing, checking, selecting or setting a slider, it matches the label on whole words, so "PIN" never matches "Pincode".
  • Second look, without a second press. If a tap or navigation can't be confirmed right away, the SDK looks again about 1.5 s later, so a slow network response still counts as success. It never presses anything twice.
  • Richer results for the agent. Each result says what was requested, what was acted on and whether it was verified. Multi-step results report which step ended the mission and how many steps completed, so the agent can explain exactly what happened.
  • Richer screen data. Disabled state, input hints, slider ranges, parent/child structure, a "can type here" action on text fields, and role names that match the Android SDK (switch, radio, navigation, listitem, modal, …). An element counts as visible only when at least 5% of it is on screen.
  • Icon-only controls and custom tab bars. Unlabelled icon buttons are named from their image file or icon. Hand-built bottom navigation bars are recognised as tabs, and the active tab is inferred when only one item is drawn differently. "Go back" after a custom tab switch returns to the previous tab.
  • Faster cancels and multi-step missions. Cancels and newer missions take effect immediately. A step that follows a screen change waits up to 2 s for the next screen. Missions that continue on failure report each failed step and keep going.
  • Guided highlights find, scroll to and re-check their target before drawing, and stay until cleared when the agent asks.
  • New remote switch. You can turn off the native tap fallback from your Revrag configuration. Normal accessibility taps are unaffected.

Fixed

  • Animation durations of 0 from the backend no longer crash the highlight, border or awakening effects.
  • In release builds, analytics IDs for some widgets no longer collapse to Instance of …. Analytics IDs for strings, numbers, enums, dates and lists are unchanged from 0.2.0.
  • Release builds no longer print wire traffic. Debug logs hide secrets (API keys, tokens, PINs, OTPs, passwords, phone numbers and email addresses) and any text the agent types.
  • A dialog no longer hides on-screen content outside it, an inline dialog no longer turns its whole page into an overlay, and sheet backdrops are attached to their sheet.
  • Large screens are trimmed to fit the transport limit instead of being dropped. A response that can't be sent becomes an explicit failure, so the agent never waits forever.
  • Screen-cache sync is more robust. It retries when the backend stored nothing, quarantines a single file the backend keeps rejecting so the rest still sync, and starts as soon as it is allowed.
  • The SDK's own panel is no longer captured as part of your app.
  • The fallback tap only fires when the control is at least half visible and actually reachable. A tap with no visible effect is never retried, so there are no double side effects.

Upgrade steps: 0.2.0 → 0.3.0

  1. Make sure your project uses Flutter 3.29+ (flutter --version).
  2. Update pubspec.yaml to embed_flutter: ^0.3.0 and run flutter pub get.
  3. Check disabledRoutes. It is now the one list that keeps the agent away from a screen. Add any sensitive named dialogs or sheets to it.
  4. Recommended: name every route, give tab roots a ValueKey<String>, label icon-only buttons with Semantics(label: …), and add Semantics(selected: …) / Semantics(checked: …) to custom tabs, chips and radios.
  5. Rebuild and test a few agent actions on a real device.

0.2.0

Released: September 2026

The native-parity release — config wiring, call/agent modes, back navigation, widget UX, and the action-intelligence runtime brought in line with the Android and React Native SDKs, plus an on-device UI-graph cache and a hardened no-crash guarantee for the host app. Verified live on a physical device. Upgrading from 0.0.x requires a few code changes; work through the upgrade steps below.

Breaking changes

ChangeWhat to do
Multi-agent (flowName) removedOne integration is one agent (React / React Native parity). Drop flowName from embedInitialize / embedEvent / embedTrack*; enabledRoutes becomes a flat List<String>; per-flow groupContinuity / groupDelays collapse to continuity: / buttonDelay: (or the new buttonVisibility groups). Existing on-device caches stay valid; multi-agent apps must split into separate integrations.
embedInitialize is the single, all-named intakeembedInitialize(apiKey: …, appVersion: …, embedUrl: …). apiKey moved from positional to a required named parameter; appVersion is now required (embedSetAppVersion() and the package_info_plus auto-derivation are gone).
EmbedProvider removedIt only forwarded credentials and mounted an EmbedWidget. Call embedInitialize before runApp and wrap with EmbedWidget directly.
Host position/color props removedDelete apiKey / embedUrl / primaryColor / rightPadding / bottomPadding / groupInsets (and EmbedButtonInset) from EmbedWidget. FAB position (widget_config.position) and colors (widget_config.colorPalette) now come from the dashboard.
Server-driven panels/cards render only in workflow modeA call started from the FAB (or the inactivity auto-trigger) is co-pilot and drops inbound panel frames. To keep panels, start from host code: EmbedWidget.startCall(agentTriggerMode: AgentTriggerMode.WORKFLOW).
other_data flags removedMove opt-outs to action_config.flags.dataCapture (snapshot/capture) and EmbedWidget(usePlatformRouteAllowlist: true) (route allowlist).

New

  • AgentTriggerMode (co-pilot / workflow) — host-declared at EmbedWidget.startCall(agentTriggerMode:) and latched per call; decides who owns the UI, whether panels render, and whether the avatar surface opens. Enum values CO_PILOT / WORKFLOW (identifier-for-identifier with Android); cross-SDK wire string is lowercase copilot / workflow (mode.wire / parseAgentTriggerMode(...)).
  • Host-crash safety net — embedInitialize installs a chained PlatformDispatcher.onError guard that swallows only livekit_client / flutter_webrtc async errors and delegates everything else to the host's handler. Combined with type-coerced config and fully guarded timers/listeners, nothing the SDK does can crash the host app.
  • On-device UI-graph cache + sync — screens are captured to a durable on-disk store (one JSON file per screen) and synced to the backend, gated by the dashboard action_config.flags.dataCapture master switch.
  • Visibility groups (buttonVisibility) — EmbedWidget(buttonVisibility: EmbedButtonVisibilityConfig(groups: [...])); each group gives a set of screens its own FAB continuity / delay / delay-policy (first matching group wins; a group's screens also join the allow-list).
  • New host controls — EmbedWidget.expandWidget() (programmatic inverse of collapseWidget(), emits agent_tap_to_open; startCall() does not auto-expand) and EmbedWidget.openAvatarScreen() (opens the full-screen agent surface, starting a workflow call if none is running).
  • action_config / widget_config coverage completed — dataCapture master gate; awakeningEffect / activeBorderGlow / highlighting / clickTracking kill-switches; all 26 effects.* tuning knobs; position.* and agentAvatar.avatarSize merged; isCollapsed opening state honored once per widget lifetime.
  • call_id — latched from /token and sent flat on agent_conversation_started / _ended (Android parity).
  • System-back rung — back now sweeps every reachable navigator (deepest-first, PopScope-aware), so nested / per-tab hosts no longer exhaust the find ladder.

Fixed / clarified

  • Inactivity/nudge parity: nudgeDelay <= 0 = off; the popup shows only with a non-empty tooltip; captions suppress the auto-collapse and cancel a running countdown.
  • Widget UX: one centered expanded-bar width; awakening plays only while no call is live; collapse artifacts fixed; a silent config revalidate no longer collapses an open bar; the avatar can no longer surface on a co-pilot call.
  • Memory (OOM guard): the exploration log is now call-scoped and LRU-capped to 12 screens — it can no longer grow unbounded across calls in a long-lived host process.
  • No double submits: a semantic tap/navigate that fired but produced zero observable evidence now fails after one attempt; rely on the backend failure_reason: tap_had_no_observable_effect to re-plan.
  • Secure fields: capture-time (sticky) redaction — typed field contents no longer ride text or stable ids.
  • Config cache un-brick: cached config is versioned with TTL + revalidate, so a stale cache can no longer hide the widget for the life of the install.

Upgrade steps: 0.0.x → 0.2.0

  1. Bump embed_flutter to ^0.2.0 in pubspec.yaml, then flutter pub get and (iOS) pod install. Re-check platform floors in the Compatibility & Dependency Matrix.
  2. Move credentials into embedInitialize (named, required): embedInitialize('KEY', flowName: 'main') → embedInitialize(apiKey: 'KEY', appVersion: '1.0.0'). Delete any embedSetAppVersion() call.
  3. Drop EmbedProvider — call embedInitialize before runApp and wrap with EmbedWidget directly.
  4. Flatten enabledRoutes: {'main': ['home', 'account']} → ['home', 'account'].
  5. Remove host position/color props (apiKey / embedUrl / primaryColor / rightPadding / bottomPadding / groupInsets) from EmbedWidget; set position and colors from the dashboard.
  6. Replace groupContinuity / groupDelays with continuity: / buttonDelay:, or model per-screen behavior with buttonVisibility groups.
  7. If you rely on server-driven panels/cards, start the call in workflow mode: EmbedWidget.startCall(agentTriggerMode: AgentTriggerMode.WORKFLOW).
  8. Rebuild fully and re-test a call on a real device.

0.0.20 and earlier

The pre-parity line: floating voice-agent FAB (LiveKit), flow-scoped enabledRoutes with flowName, EmbedProvider, host-side FAB positioning (rightPadding / bottomPadding), the four event keys (USER_DATA, SCREEN_STATE, CUSTOM_EVENT, ANALYTICS_DATA), FAB pre-show delays (0.0.18), and Bluetooth-headset audio fixes (0.0.20). No agent trigger modes, no UI-graph cache, no crash guard, no visibility groups. If you are still on 0.0.x, upgrade via the steps above — the 0.0.x line is not maintained.



Support