flutter_netwatch
A production-grade Flutter HTTP inspector with sensitive data masking, cURL export, Postman export, security analysis, floating bubble UI, and QA-ready notifications.
Demo
The recording shows a real Flutter app running with flutter_netwatch wired in:
- The app fires HTTP requests through Dio.
- Each request shows up live in the floating bubble (top-right) with an unseen-count badge.
- Tap the bubble to open the full-screen inspector — list filters by 2xx / 3xx / 4xx / 5xx / slow / errors.
- Tap a transaction to inspect URL, headers, body, and security analysis.
- Toggle the lock icon to mask sensitive headers / fields / query params live.
- FAB Export opens cURL, Postman, and plain-text export options.
Full-quality MP4: assets/demo.mp4
- Zero navigator conflicts — works with any
MaterialAppsetup - Runtime-configurable via
NetWatchConfig.enabled - Sealed classes throughout — exhaustive pattern matching
- No native dependencies — pure Flutter Overlay
- Supports Dio, http, and Chopper
Install
dependencies:
flutter_netwatch: ^0.3.0
Setup
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_netwatch/flutter_netwatch.dart';
import 'package:dio/dio.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
NetWatch.initialize(
config: NetWatchConfig(
enabled: !kReleaseMode,
maskSensitiveData: true,
showFloatingBubble: true,
showNotifications: true,
maxTransactions: 200,
performanceBudgetMs: 1000,
),
);
final dio = Dio();
dio.interceptors.add(NetWatch.dioInterceptor);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: NetWatch.builder, // only required change
home: HomeScreen(),
);
}
}
Three setup scenarios — all work without conflict
A) No existing navigator key
MaterialApp(
builder: NetWatch.builder,
home: HomeScreen(),
)
B) Existing key + observer
MaterialApp(
navigatorKey: myKey,
navigatorObservers: [NetWatch.observer],
builder: NetWatch.builder,
)
C) Existing key only — zero observer
MaterialApp(
navigatorKey: myKey,
builder: NetWatch.builder,
)
NetWatch never pushes routes onto your navigator. The inspector opens as an OverlayEntry over the app inside its own Overlay.
Other clients
http
import 'package:http/http.dart' as http;
final client = NetWatch.httpClient(http.Client());
await client.get(Uri.parse('https://api.example.com/users'));
Chopper
final chopperClient = ChopperClient(
interceptors: [NetWatch.chopperInterceptor],
);
Features
In-app inspector
Tap the floating bubble (or call NetWatch.open()) to launch the full-screen inspector. Filter by status (2xx, 3xx, 4xx, 5xx, slow, errors), search by URL/method/status, and tap any row for full request/response/security details.
Customizing the floating bubble
Want your own look for the floating button? Pass a bubbleBuilder to the config. You get the live unseen-request count and the open callback; NetWatch keeps handling drag, edge-snapping, and the long-press quick-stats menu — you only own the visual.
NetWatch.initialize(
config: NetWatchConfig(
bubbleBuilder: (context, unseenCount, openInspector) {
return FloatingActionButton(
onPressed: openInspector,
child: Badge.count(
isLabelVisible: unseenCount != 0,
count: unseenCount,
child: const Icon(Icons.wifi_tethering),
),
);
},
),
);
Leave bubbleBuilder unset to use the built-in bubble (eye icon + unseen-count badge).
Sensitive data masking
Headers like Authorization, Cookie, X-API-Key, body fields like password, token, secret, and URL query params like ?token=... are masked automatically. Toggle masking on/off live in the UI — affects every export.
NetWatch.initialize(
config: NetWatchConfig(
sensitiveHeaders: [
...NetWatchConfig.defaultSensitiveHeaders,
'x-my-custom-token',
],
sensitiveBodyFields: [
...NetWatchConfig.defaultSensitiveBodyFields,
'pin_code',
],
),
);
Exporters
- cURL — copy/share any request as a runnable cURL command.
- Postman — export single request or full collection (Postman Collection v2.1).
- HAR — Chrome DevTools / Charles / Insomnia / Fiddler-compatible.
- Plain text — share complete request/response details.
Replay
Re-fire any captured request with one tap from the detail screen. Register a replayer once with the same HTTP client you're already capturing through:
final dio = Dio();
dio.interceptors.add(NetWatch.dioInterceptor);
NetWatch.registerReplayer(NWDioReplayer(dio)); // ← one line
For http:
final client = NetWatch.httpClient(http.Client());
NetWatch.registerReplayer(NWHttpClientReplayer(client));
For Chopper or any custom client:
NetWatch.registerReplayer(NWCustomReplayer(
canHandle: (req) => req.url.host == 'api.mybackend.com',
replay: (req) async {
// re-fire `req` through your client of choice
},
));
The Replay FAB only appears when at least one registered replayer's canHandle() returns true for that request — so you can register multiple replayers and route by host or method.
GraphQL pretty-print
NetWatch detects GraphQL operations on the wire automatically. The transaction list shows the operation name (GetUserProfile, UpdateOrder, etc.) instead of the path, with a magenta GQL badge. The detail screen splits the body into query / variables / data / errors sections.
Stats screen
Tap the bar-chart icon in the inspector AppBar for a live dashboard: total / success / failure / success-rate, avg / p95 / max duration, top-5 slowest endpoints, top-5 most-failing endpoints, and a per-host bar chart.
Security analysis
Each captured request is checked for:
- HTTPS usage
- HSTS / X-Content-Type-Options / CSP headers
- Sensitive data in URL query params
- Basic auth scheme usage
A rating (good / warning / critical) is computed per request.
Performance budget
Requests slower than the configured budget (performanceBudgetMs, default 1000ms) are flagged as NWStatusSlow.
Programmatic API
NetWatch.open(); // open inspector
NetWatch.clear(); // clear captured transactions
NetWatch.transactions; // List<NWTransaction>
NetWatch.transactionStream; // Stream<List<NWTransaction>>
NetWatch.isActive; // reflects initialize() + config.enabled
Enabling capture in release builds
By default, NetWatchConfig.enabled is !kReleaseMode, so copy-paste setup stays off in release builds.
To capture release-build traffic deliberately, opt in:
NetWatch.initialize(
config: const NetWatchConfig(
enabled: true,
),
);
NetWatch follows NetWatchConfig.enabled in every build mode. When enabled is false:
NetWatch.builderbecomes a pass-through wrapper.- Interceptors are no-ops — they call
handler.next()immediately. - The core singleton stays inactive and no transactions are stored.
When enabled is true, capture and UI stay available even in release builds. That makes it possible to profile real release performance while still inspecting live HTTP traffic.
Related Packages
- flutter_release_checklist — Pre-release security and quality CLI
Author
Built by Mujtaba — software engineer working on Flutter, AI, and developer tooling.
Support
If this package saves your team time, consider sponsoring:
License
MIT
Libraries
- flutter_netwatch
- Production-grade Flutter HTTP inspector.