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.
Libraries
- dio_network_inspector
- An in-app network inspector for Dio.

