Network Inspection
Capture and inspect HTTP network calls from Dio or any dart:io HttpClient.
The network inspector captures every HTTP request, response, and error made through your HTTP client, storing them in memory for real-time inspection.
Packages
| Use case | Package |
|---|---|
| Dio | xray_network_dio_interceptor |
All dart:io clients (Dio, package:http, and any other client that delegates to dart:io) | xray_inspector (enableHttpOverride) |
Setup with Dio
import 'package:xray_inspector/xray_inspector.dart';
import 'package:xray_network_dio_interceptor/xray_network_dio_interceptor.dart';
import 'package:dio/dio.dart';
final networkInspector = XRayNetworkInspector();
final dio = Dio()
..interceptors.add(
XRayNetworkDioInterceptor(inspector: networkInspector),
);
Setup with global HTTP override
Pass enableHttpOverride: true to intercept every HTTP request made in the app at the dart:io level — Dio, package:http, and any other client that uses dart:io under the hood. No changes to individual clients are needed.
import 'package:xray_inspector/xray_inspector.dart';
final networkInspector = XRayNetworkInspector(enableHttpOverride: true);
The HTTP override captures all traffic in the process, regardless of which HTTP client made the call. If you also use a Dio interceptor, Dio calls will appear in both inspectors — the Dio inspector and the HTTP override inspector.
Only one XRayNetworkInspector can have enableHttpOverride: true at a time. Enabling it on a second inspector throws a StateError at startup.
enableHttpOverride is silently ignored on web — dart:io is not available there.
Accessing captured calls
// All captured calls (snapshot)
final calls = networkInspector.calls;
// Reactive — rebuilds your widget when calls change
ValueListenableBuilder<List<XRayNetworkCall>>(
valueListenable: networkInspector.callsNotifier,
builder: (context, calls, _) {
return Text('${calls.length} calls captured');
},
);
Listening to new calls in code
Implement XRayNetworkInterceptorListener and register it:
class MyListener implements XRayNetworkInterceptorListener {
@override
void onNetworkCallAdded(XRayNetworkCall call) {
debugPrint('[Network] ${call.method} ${call.uri} → ${call.responseStatusCode}');
}
}
final listener = MyListener();
networkInspector.addListener(listener);
// Clean up when done
networkInspector.removeListener(listener);
Custom inspector title
final networkInspector = XRayNetworkInspector(title: 'API Calls');
The title is displayed in the remote UI and used to generate the inspector's ID.
Network call model
Each captured call is an XRayNetworkCall with these fields:
| Field | Type | Description |
|---|---|---|
id | String | Unique ID (timestamp-based) |
method | String | HTTP method (GET, POST, etc.) |
uri | String | Full request URI |
requestHeaders | Map<String, dynamic>? | Request headers |
requestBody | dynamic | Request body |
responseStatusCode | int? | HTTP status code |
responseHeaders | Map<String, dynamic>? | Response headers |
responseBody | dynamic | Response body |
status | XRayNetworkCallStatus | loading / success / error |
startTime | DateTime | When the request started |
endTime | DateTime? | When the request completed |
durationMs | int? | Duration in milliseconds |
error | String? | Error message if failed |
Multiple network inspectors
You can run multiple network inspectors simultaneously. Each must have a distinct title (used to generate the inspector's ID). A common pattern is one inspector for Dio and one for all other HTTP traffic:
final networkDioInspector = XRayNetworkInspector(title: 'Network (Dio)');
final networkHttpInspector = XRayNetworkInspector(
title: 'Network (Http)',
enableHttpOverride: true,
);
final dio = Dio()
..interceptors.add(XRayNetworkDioInterceptor(inspector: networkDioInspector));
In this setup, Dio calls will appear in both inspectors — the Dio interceptor captures them with richer metadata, while the HTTP override captures them at the lower dart:io level.

