Inline WebView
InAppWebView renders a WebView inside the Flutter widget tree. It is the right choice when the WebView belongs to a screen and should participate in that screen's layout and lifecycle.
Initial content
Use one of the initial content options:
InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri('https://example.com'),
),
)InAppWebView(
initialFile: 'assets/website/index.html',
)InAppWebView(
initialData: InAppWebViewInitialData(
data: '<h1>Hello</h1>',
baseUrl: WebUri('https://example.com/'),
),
)Use only one initial content source for a WebView. Later navigation should be performed through the controller.
Settings
Prefer initialSettings for new code:
InAppWebView(
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
mediaPlaybackRequiresUserGesture: true,
disableAutocorrection: true,
),
)initialOptions and the older option classes remain available for compatibility, but they are deprecated. See Deprecated APIs for the Options-to-Settings, callback, and type-name mapping. Settings that are not supported by a platform are ignored or use that platform's fallback behavior. Check runtime capability before depending on a platform-specific setting.
Useful settings include:
disableAutocorrectionfor editable HTML elements;containerIdfor a named storage profile where the platform supports it;proxySettingsfor per-WebView proxy configuration where supported;javaScriptBridgeEnabledand origin allowlists for bridge control;useHybridCompositionon Android when choosing a platform-view mode;useWebViewBuilderandwebViewBuilderOriginAllowListon Android whenWebViewFeature.WEBVIEW_BUILDERis supported;writingToolsBehavioron Apple platforms where Writing Tools are available;allowsInlinePredictionson Apple platforms;conversationContexton iOS 26+ for Smart Reply;backForwardCacheEnabled,backForwardCacheTimeoutSeconds, andbackForwardCacheMaxPagesInCacheon Android when BFCache features are supported;obscuredContentInsetson iOS/macOS 26+ when the WebView is under system chrome.
JavaScript
final result = await controller.evaluateJavascript(
source: 'document.title',
);For a structured asynchronous JavaScript operation, use callAsyncJavaScript. Treat returned values as nullable and validate their shape before using them in application logic.
JavaScript bridge
Register a handler from Dart:
controller.addJavaScriptHandler(
handlerName: 'appBridge',
callback: (arguments) {
return {'ok': true, 'received': arguments};
},
);Call it from the page:
window.flutter_inappwebview.callHandler('appBridge', {action: 'refresh'});Only expose handlers that the page is allowed to call. For untrusted or multi-tenant content, use the bridge origin allowlist and validate every argument in Dart.
Keep the controller and WebView identity stable
Do not create a new InAppWebView controller or InAppWebViewKeepAlive inside build(). Rebuilding the widget is normal; recreating the native WebView is expensive and can reset page state, JavaScript state, and scroll position. See Preload and reuse for route transitions.
Mute, downloads, and first paint
Mute audio when the provider supports it. On Android this is WebViewFeature.MUTE_AUDIO; on iOS/macOS it maps to media playback suspension:
if (InAppWebViewController.isMethodSupported(
PlatformInAppWebViewControllerMethod.setAudioMuted,
) ||
await WebViewFeature.isFeatureSupported(WebViewFeature.MUTE_AUDIO)) {
await controller.setAudioMuted(muted: true);
}Return null from onDownloadStarting to keep notify-only behavior. Return DownloadStartResponse(handled: true, resultFilePath: absolutePath) only when the application wants a native download job (Android, iOS, macOS, Windows). Android onVisualStateReady fires after postVisualStateCallback or after a finished load. Use saveStateWithOptions on Android when the provider supports size or forward-history controls.
Android navigation and profile warmup
// NavigationParameters when supported:
await controller.navigate(
url: WebUri('https://example.com/docs'),
replaceHistory: false,
headers: {'X-Forge-Demo': '1'},
);
// Profile warmup before attaching a container WebView:
final containers = ContainerController.instance();
await containers.preconnect(
containerId: 'work',
url: 'https://example.com/',
);BFCache and WebViewBuilder
InAppWebView(
initialSettings: InAppWebViewSettings(
backForwardCacheEnabled: true,
backForwardCacheTimeoutSeconds: 60,
backForwardCacheMaxPagesInCache: 3,
useWebViewBuilder: true,
webViewBuilderOriginAllowList: {'https://example.com'},
),
)Check WebViewFeature.BACK_FORWARD_CACHE_SETTINGS and WebViewFeature.WEBVIEW_BUILDER on Android before depending on these settings.
iOS 26 conversation context
When Smart Reply or related WebKit features need thread metadata, set conversationContext at creation time and gate with InAppWebViewSettings.isPropertySupported( InAppWebViewSettingsProperty.conversationContext). See Examples and recipes for a sample map shape.