StorytellerEmbeddedClipsView lets you place the native Storyteller clips experience inline within your Flutter UI while keeping full control of layout, scrolling, and lifecycle.
Initialize successfully before mounting the view. Use a Clips collection containing published content for your API key and give the view bounded width and height.
The placement defaults below are verified for Flutter 12.1.2
(Android 12.2.0 / iOS 11.9.0) and 11.6.5 (Android 11.6.4 / iOS
11.6.1). Current bridge limitations are identified against the 12.1.2
audit baseline; compare Changelog.
classInlineClipsextendsStatelessWidget{constInlineClips({super.key});@overrideWidgetbuild(BuildContextcontext){returnSizedBox(height:420,child:StorytellerEmbeddedClipsView(collectionId:'featured-highlights',openReason:StorytellerOpenReason.instanceMethod,shouldPlay:true,topLevelBack:false,onDataLoadStarted:()=>debugPrint('Loading clips...'),onDataLoadComplete:(result){if(!result.success){debugPrint('Clips failed to load: ${result.error}');}else{debugPrint('Embedded Clips loaded successfully');}},),);}}
Key parameters:
collectionId(required) – the Storyteller collection to play.
clipId – start playback at a specific clip.
initialCategory – open the embedded UI within a category.
openReason – optional analytics attribution using StorytellerOpenReason.instanceMethod or StorytellerOpenReason.deeplink. Omit it to preserve the native Embedded Clips default.
shouldPlay – autoplay behaviour (defaults to true).
isVisible – native platform-view visibility (defaults to true). Set this to false when retaining the player in an inactive tab.
topLevelBack – whether to enable top-level back behavior (defaults to false). Flutter does not expose the native top-level-back tap callback.
theme – apply a StorytellerTheme override.
context – attach analytics attribution on iOS; the current Android embedded bridge ignores this value.
topInset / bottomInset – provide safe area values in logical pixels. Consumed at creation on Android only; iOS ignores these values. Both default to 0.
Pre-roll is supported on Android and iOS. Omit the nullable value to preserve
the native default; Android defaults it on and iOS defaults it off in both
compared baselines. Provider ordering remains Android-only.
All three fields are nullable. Only values you explicitly supply are sent to native
code; the linked native SDK chooses defaults for missing fields. Provider
ordering is supported on Android in both compared Flutter baselines and ignored
on iOS. A null order
keeps native module order, an empty list disables standard between-Clips
providers for this presentation, and a populated list restricts and orders
them. Omitting the whole adConfiguration object keeps the native Embedded
Clips defaults for the current platform and SDK version.
For a production-ready configuration (including safe-area handling and controller-driven playback), review the Showcase MomentsScreen.
Two callbacks are emitted by the current native bridges:
onDataLoadStarted() – when Storyteller begins loading collection data.
onDataLoadComplete(StorytellerEmbeddedClipsLoadResult result) – inspect result.success and result.error. Android provides a clip count in dataCount; iOS maps success to 1 and failure to 0, so its value is not a clip count.
The Dart constructor also accepts onUserActivityOccurred, but neither current native bridge emits that widget callback. Subscribe to the global analytics stream and use analytics attribution where available. Android's Embedded Clips bridge currently does not forward the widget's context value. These limitations apply to the audited 12.1.2 wrapper. See Changelog for other versions.
Attach a StorytellerEmbeddedClipsController to pause/resume playback, update retained-view visibility, reload data, or query the native back-navigation state, with the Android limitation below.
canGoBack() – iOS reports nested back availability. In Flutter 12.1.2 with Android 12.1.2, this value is inverted relative to goBack(); do not use it to gate Android nested navigation.
goBack() – navigate back on Android. The current iOS Flutter bridge accepts this call but performs no action.
setShouldPlay(bool) – toggle playback.
setIsVisible(bool) – show or hide the retained native platform view without disposing its player state.
updateInsets({int top = 0, int bottom = 0}) – exposed by Dart, but not a working safe-area update in the current bridges: iOS performs no action and Android resets native insets to zero. For Android insets, set the widget's logical-pixel topInset and bottomInset at creation; recreate it with a new key when those values change.
Playback and visibility have separate controls. setShouldPlay(false) keeps an onscreen player rendered in its paused state. On Android, hiding a retained player also pauses native playback, even when shouldPlay is true; the player's state is retained. For an IndexedStack or another retained tab container, call setIsVisible(false) when that tab becomes inactive so native view-based ad media also receives a real visibility transition. Restore visibility before resuming playback when the tab becomes active again.
On Android, a retained player hidden with isVisible: false or setIsVisible(false) does not consume first-run Clips Instructions. They remain available to the first visible eligible player, whether full-screen or embedded.
Calls made before the platform view is created are ignored (the embedded clips controller does not queue commands). Invoke controller methods after the view has attached, such as from a native load callback or subsequent user interaction; a first-frame callback alone does not prove attachment.
Widget arguments configure the platform view when created. Rebuilding the same widget does not update native presentation parameters: use controller methods for playback/visibility changes and a new key for collection, destination, theme or ad configuration changes. A first-frame callback is not a readiness guarantee; pre-attachment controller calls are ignored. For loading or lifecycle problems, see Troubleshooting; for provider registration, see Ads.
{"slug": "embedded-clips", "page_title": "Embedded Clips", "page_url": "EmbeddedClips/", "canonical_url": "/flutter/EmbeddedClips/", "markdown": "# Embedded Clips\n\n`StorytellerEmbeddedClipsView` lets you place the native Storyteller clips experience inline within your Flutter UI while keeping full control of layout, scrolling, and lifecycle.\n\nInitialize successfully before mounting the view. Use a Clips collection containing published content for your API key and give the view bounded width and height.\n\nThe placement defaults below are verified for Flutter `12.1.2`\n(Android `12.2.0` / iOS `11.9.0`) and `11.6.5` (Android `11.6.4` / iOS\n`11.6.1`). Current bridge limitations are identified against the `12.1.2`\naudit baseline; compare [Changelog](Changelog.md).\n\n## Basic usage\n\n```dart\nclass InlineClips extends StatelessWidget {\n const InlineClips({super.key});\n\n @override\n Widget build(BuildContext context) {\n return SizedBox(\n height: 420,\n child: StorytellerEmbeddedClipsView(\n collectionId: 'featured-highlights',\n openReason: StorytellerOpenReason.instanceMethod,\n shouldPlay: true,\n topLevelBack: false,\n onDataLoadStarted: () => debugPrint('Loading clips...'),\n onDataLoadComplete: (result) {\n if (!result.success) {\n debugPrint('Clips failed to load: ${result.error}');\n } else {\n debugPrint('Embedded Clips loaded successfully');\n }\n },\n ),\n );\n }\n}\n```\n\nKey parameters:\n\n- `collectionId` *(required)* \u2013 the Storyteller collection to play.\n- `clipId` \u2013 start playback at a specific clip.\n- `initialCategory` \u2013 open the embedded UI within a category.\n- `openReason` \u2013 optional analytics attribution using `StorytellerOpenReason.instanceMethod` or `StorytellerOpenReason.deeplink`. Omit it to preserve the native Embedded Clips default.\n- `adConfiguration` \u2013 optional per-presentation `StorytellerClipsAdConfiguration` controlling first-Clip pre-roll, bottom-banner placement, and Android between-Clips provider ordering.\n- `shouldPlay` \u2013 autoplay behaviour (defaults to `true`).\n- `isVisible` \u2013 native platform-view visibility (defaults to `true`). Set this to `false` when retaining the player in an inactive tab.\n- `topLevelBack` \u2013 whether to enable top-level back behavior (defaults to `false`). Flutter does not expose the native top-level-back tap callback.\n- `theme` \u2013 apply a `StorytellerTheme` override.\n- `context` \u2013 attach analytics attribution on iOS; the current Android embedded bridge ignores this value.\n- `topInset` / `bottomInset` \u2013 provide safe area values in logical pixels. Consumed at creation on Android only; iOS ignores these values. Both default to `0`.\n\n## Configure ad placements for one presentation\n\nPass an ad configuration only when this Embedded Clips instance needs to\noverride native placement behavior:\n\n```dart\nStorytellerEmbeddedClipsView(\n collectionId: 'featured-highlights',\n adConfiguration: const StorytellerClipsAdConfiguration(\n preRollEnabled: true,\n bottomBannerEnabled: true,\n betweenClipsAdProviderOrder: [\n StorytellerAdProvider.gam,\n StorytellerAdProvider.vast,\n ],\n ),\n)\n```\n\nPre-roll is supported on Android and iOS. Omit the nullable value to preserve\nthe native default; Android defaults it on and iOS defaults it off in both\ncompared baselines. Provider ordering remains Android-only.\n\nAll three fields are nullable. Only values you explicitly supply are sent to native\ncode; the linked native SDK chooses defaults for missing fields. Provider\nordering is supported on Android in both compared Flutter baselines and ignored\non iOS. A `null` order\nkeeps native module order, an empty list disables standard between-Clips\nproviders for this presentation, and a populated list restricts and orders\nthem. Omitting the whole `adConfiguration` object keeps the native Embedded\nClips defaults for the current platform and SDK version.\n\nFor a production-ready configuration (including safe-area handling and controller-driven playback), review the Showcase [`MomentsScreen`](https://github.com/getstoryteller/storyteller-showcase-flutter/blob/main/lib/screens/moments/moments_screen.dart#L219).\n\n## React to embedded callbacks\n\nTwo callbacks are emitted by the current native bridges:\n\n- `onDataLoadStarted()` \u2013 when Storyteller begins loading collection data.\n- `onDataLoadComplete(StorytellerEmbeddedClipsLoadResult result)` \u2013 inspect `result.success` and `result.error`. Android provides a clip count in `dataCount`; iOS maps success to `1` and failure to `0`, so its value is not a clip count.\n\nThe Dart constructor also accepts `onUserActivityOccurred`, but neither current native bridge emits that widget callback. Subscribe to the global [analytics stream](StorytellerDelegate.md#onuseractivityoccurred) and use analytics attribution where available. Android's Embedded Clips bridge currently does not forward the widget's `context` value. These limitations apply to the audited 12.1.2 wrapper. See [Changelog](Changelog.md) for other versions.\n\n## Control playback programmatically\n\nAttach a `StorytellerEmbeddedClipsController` to pause/resume playback, update retained-view visibility, reload data, or query the native back-navigation state, with the Android limitation below.\n\n```dart\nclass ControllableEmbeddedClips extends StatefulWidget {\n const ControllableEmbeddedClips({super.key});\n\n @override\n State<ControllableEmbeddedClips> createState() =>\n _ControllableEmbeddedClipsState();\n}\n\nclass _ControllableEmbeddedClipsState\n extends State<ControllableEmbeddedClips> {\n final _controller = StorytellerEmbeddedClipsController();\n\n @override\n Widget build(BuildContext context) {\n return Column(\n children: [\n Expanded(\n child: StorytellerEmbeddedClipsView(\n collectionId: 'live-stream',\n controller: _controller,\n shouldPlay: false,\n ),\n ),\n FilledButton(\n onPressed: () async {\n await _controller.setShouldPlay(true);\n },\n child: const Text('Play clips'),\n ),\n ],\n );\n }\n}\n```\n\nAvailable controller actions:\n\n- `reloadData()` \u2013 refreshes the native data source.\n- `canGoBack()` \u2013 iOS reports nested back availability. In Flutter 12.1.2 with Android 12.1.2, this value is inverted relative to `goBack()`; do not use it to gate Android nested navigation.\n- `goBack()` \u2013 navigate back on Android. The current iOS Flutter bridge accepts this call but performs no action.\n- `setShouldPlay(bool)` \u2013 toggle playback.\n- `setIsVisible(bool)` \u2013 show or hide the retained native platform view without disposing its player state.\n- `updateInsets({int top = 0, int bottom = 0})` \u2013 exposed by Dart, but not a working safe-area update in the current bridges: iOS performs no action and Android resets native insets to zero. For Android insets, set the widget's logical-pixel `topInset` and `bottomInset` at creation; recreate it with a new key when those values change.\n\nPlayback and visibility have separate controls. `setShouldPlay(false)` keeps an onscreen player rendered in its paused state. On Android, hiding a retained player also pauses native playback, even when `shouldPlay` is `true`; the player's state is retained. For an `IndexedStack` or another retained tab container, call `setIsVisible(false)` when that tab becomes inactive so native view-based ad media also receives a real visibility transition. Restore visibility before resuming playback when the tab becomes active again.\n\nOn Android, a retained player hidden with `isVisible: false` or `setIsVisible(false)` does not consume first-run Clips Instructions. They remain available to the first visible eligible player, whether full-screen or embedded.\n\nCalls made before the platform view is created are ignored (the embedded clips controller does not queue commands). Invoke controller methods after the view has attached, such as from a native load callback or subsequent user interaction; a first-frame callback alone does not prove attachment.\n\nWidget arguments configure the platform view when created. Rebuilding the same widget does not update native presentation parameters: use controller methods for playback/visibility changes and a new key for collection, destination, theme or ad configuration changes. A first-frame callback is not a readiness guarantee; pre-attachment controller calls are ignored. For loading or lifecycle problems, see [Troubleshooting](Troubleshooting.md); for provider registration, see [Ads](Ads.md).\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}