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.

pub package CI License: MIT

Calls Detail
List of captured calls with method, status and latency Call detail showing response headers and pretty-printed JSON

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 (5 matches 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.