💉Injecting JavaScript in Flutter WebView — A Complete Guide 📖
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Flutter's webview_flutter is powerful for embedding web content, but sometimes you need more than just loading a page.
👉 What if you want to:
- Capture form input values (like username or email)?
- Modify DOM elements dynamically?
- Add custom click listeners?
- Communicate between the web page and Flutter?
This is where JavaScript injection comes in.
In this guide, we'll learn how to inject JavaScript into a WebView, capture values, and send them back to Flutter.
📦 Adding webview_flutter
To get started, add the package to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.8.0
webview_flutter | Flutter package(Always check pub.dev for the latest version.)
A Flutter plugin that provides a WebView widget backed by the system webview.
pub.dev
⚙️ Setting Up WebView
First, let's set up a WebView with unrestricted JavaScript enabled:
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("Captured from WebView: ${message.message}");
},
)
..loadRequest(Uri.parse("https://example.com/login"));
Here, we've created a JavaScript channel (FormChannel) that acts like a "bridge" between JavaScript and Flutter.
🧑‍💻 Injecting JavaScript
Now, let's inject some JavaScript when the page finishes loading:
Future<void> _injectCustomHook() async {
await _controller.runJavaScript('''
(function() {
const loginButton = document.querySelector('button[type="submit"]');
if (loginButton) {
loginButton.addEventListener('click', function() {
const input = document.getElementById('username')?.value || '';
FormChannel.postMessage(input);
});
}
})();
''');
}🔍 What this code does
- Finds the login button inside the WebView.
- Listens for the click event.
- Reads the input field with ID username.
- Sends it back to Flutter using the FormChannel.
📥 Receiving the Data in Flutter
The data flows back into Flutter via the JavaScript channel:
..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("User typed: ${message.message}");
// Use the value in your app
},
)
If the user types hello@example.com in the web form, Flutter will print the following in the console :
User typed: hello@example.com
🚀 Why JavaScript Injection Is Powerful
With JS injection, you can:
- Capture input values before they are submitted.
- Automatically fill forms.
- Hide or restyle unwanted elements.
- Add extra functionality to existing web pages.
Example: Hide a banner inside the WebView
await _controller.runJavaScript('''
document.querySelector('.ads-banner')?.style.display = 'none';
''');đź§© Final Reference Code
Here's a complete reference combining WebView setup, JavaScript injection, and data capture:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewExample extends StatefulWidget {
const WebViewExample({super.key});
@override
State<WebViewExample> createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late final WebViewController _controller;
@override
void initState() {
super.initState();
final params = const PlatformWebViewControllerCreationParams();
final controller = WebViewController.fromPlatformCreationParams(params)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (url) {
_injectCustomHook();
},
),
)
..addJavaScriptChannel(
'FormChannel',
onMessageReceived: (JavaScriptMessage message) {
debugPrint("Captured from WebView: ${message.message}");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("User typed: ${message.message}")),
);
},
)
..loadRequest(Uri.parse("https://example.com/login"));
_controller = controller;
}
Future<void> _injectCustomHook() async {
await _controller.runJavaScript('''
(function() {
const loginButton = document.querySelector('button[type="submit"]');
if (loginButton) {
loginButton.addEventListener('click', function() {
const input = document.getElementById('username')?.value || '';
FormChannel.postMessage(input);
});
}
})();
''');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("WebView JS Injection")),
body: WebViewWidget(controller: _controller),
);
}
}
🔄 Alternatives
While webview_flutter supports basic JS injection, other packages offer more:
- flutter_inappwebview
A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser…
pub.dev
Advanced JS injection, network request interception, cookie management and Best choice if you need deep control of the page.
2. flutter_web_auth_2
flutter_web_auth_2 | Flutter packageFlutter plugin for authenticating a user with a web service.
pub.dev
Opens the system browser instead of injecting JS and Great for OAuth flows.
âś… Best Practices
- Always sanitize and validate data captured from injected JavaScript.
- Test on multiple platforms (Android & iOS behave slightly differently).
- Avoid overusing JS injection — use it only when Flutter's native APIs or backend APIs can't achieve the same.
🔥Conclusion
JavaScript injection is like giving your Flutter WebView superpowers💪. Next time you embed a web page in Flutter, don't just display it — inject your own logic and make it smarter!