dio_network_inspector 0.1.2
dio_network_inspector: ^0.1.2 copied to clipboard
An in-app network inspector for Dio — inspect, filter, and export HTTP traffic from inside your Flutter app. No plugins, no state-management lock-in.
dio_network_inspector #
An in-app network inspector for Dio. See every request your app makes, filter it, read the bodies, and export it as JSON or a cURL command — without leaving the app or attaching a proxy.
| Calls | Detail |
|---|---|
![]() |
![]() |
Why another one #
Two dependencies: dio and flutter. No native plugins, so nothing to
configure in your Podfile or Gradle, no platform restrictions, and no version
conflicts. No state-management dependency either — it is a plain
ChangeNotifier, so it drops into a Riverpod, bloc, provider, or setState
app equally well.
It also adopts your app's ColorScheme, including dark mode, instead of
shipping its own look.
Features #
- Captures every Dio request, response, and error via one interceptor
- Live list with pause, clear, and a bounded ring buffer (500 calls by default)
- Filter by HTTP method, status-code prefix (
5matches all 5xx), errors-only, and URL substring - Per-call detail: header tables and pretty-printed JSON bodies
- Copy any section, or export the request as cURL — with
Authorization,Cookie, and other auth headers automatically masked - Export the whole session as JSON
Install #
flutter pub add dio_network_inspector
Usage #
Attach the interceptor, push the page. That's the whole integration:
import 'package:dio_network_inspector/dio_network_inspector.dart';
dio.interceptors.add(NetworkInspectorInterceptor());
Navigator.of(context).push(
MaterialPageRoute<void>(builder: (_) => const NetworkInspectorPage()),
);
Both default to a shared controller, so they find each other with no wiring.
Bring your own controller #
For explicit ownership — or to keep test state isolated — construct one and pass it to both:
final inspector = NetworkInspectorController(maxCalls: 200);
dio.interceptors.add(NetworkInspectorInterceptor(inspector));
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => NetworkInspectorPage(controller: inspector),
),
);
It is a ChangeNotifier, so it slots into whatever you already use:
// Riverpod
final inspectorProvider = Provider((_) => NetworkInspectorController.instance);
// provider
ChangeNotifierProvider.value(value: NetworkInspectorController.instance);
Add the interceptor last, after anything that mutates headers or the body, so what the inspector shows is what actually went over the wire.
Theming #
Colors come from your app's ColorScheme by default. Override any slot:
NetworkInspectorPage(
theme: const InspectorTheme(
accent: Color(0xFF7C3AED),
monoFontFamily: 'JetBrainsMono',
),
)
| Slot | Used for | Default |
|---|---|---|
background |
Page background | colorScheme.surface |
surface |
Cards, list tiles, bottom sheet | colorScheme.surfaceContainerLowest |
onSurface |
Primary text | colorScheme.onSurface |
muted |
Timestamps, labels, hints | colorScheme.onSurfaceVariant |
divider |
Dividers and input borders | colorScheme.outlineVariant |
fill |
Search-field background | colorScheme.surfaceContainerHighest |
accent / onAccent |
App bar, selected chips, buttons | colorScheme.primary / onPrimary |
success / successBg |
2xx status pill | Brightness-aware green |
warning / warningBg |
3xx pill, paused banner | Brightness-aware amber |
error / errorBg |
4xx-5xx pill, error text | colorScheme.error / errorContainer |
monoFontFamily |
Headers, bodies, URLs | 'monospace' |
Unset slots fall back to the ColorScheme, so a partial override is fine.
Export #
Exports go to the clipboard by default. To hand them somewhere else — a share
sheet, a file, your bug tracker — supply onExport:
NetworkInspectorPage(
onExport: (content, suggestedFilename) =>
SharePlus.instance.share(ShareParams(text: content)),
)
It receives the session JSON, a request transcript, or a cURL command depending on which action fired, plus a suggested filename.
⚠️ Never ship this in a release build #
The detail page renders request and response headers verbatim, including
Authorization and Cookie. Masking applies only to cURL export. That is
correct for a debug tool and dangerous in production — anyone who reaches the
page can read the current user's session token.
Gate both the interceptor and the page:
if (kDebugMode) {
dio.interceptors.add(NetworkInspectorInterceptor());
}
Anything that opens the page must be behind the same check. The example app does this.
License #
MIT — see LICENSE.

