A Dio HTTP interceptor that captures all network traffic and serves a real-time web UI — like Chrome DevTools Network tab, but for your Flutter app.
Open http://localhost:8080 while your app runs and inspect every request: method, status, headers, payload, response body, timing, and more.
Features
- Dio interceptor — drop-in
Interceptorthat captures requests, responses, and errors - Real-time web UI — dark-themed dashboard with method badges, status codes, response size, duration, and syntax-highlighted JSON
- Live updates via WebSocket — new requests appear instantly without refreshing
- Request naming — give friendly names to requests via Dio's
extramap; falls back to URL - Search/filter — filter requests by URL in real time
- Responsive — card layout on mobile, table layout on desktop
- Resizable detail panel — drag to resize the headers/payload/response inspector
- Copy to clipboard — one-click copy on payload and response bodies
- Toggle at runtime — enable/disable logging, useful for production builds
Getting started
Add net_logs to your pubspec.yaml:
dependencies:
net_logs: ^0.0.5
Usage
1. Add the interceptor to Dio
import 'package:dio/dio.dart';
import 'package:net_logs/net_logs.dart';
final interceptor = NetLogsInterceptor();
final dio = Dio()..interceptors.add(interceptor);
2. Start the web server
final server = NetLogsServer(interceptor: interceptor);
await server.start(); // defaults to port 8080
3. Open the dashboard
Navigate to http://localhost:8080 in your browser. Every HTTP request made through your Dio instance will appear in real time.
Disable in production
// e.g., only enable in debug mode
if (kReleaseMode) interceptor.setEnabled(false);
Or skip starting the server entirely:
if (kDebugMode) await server.start();
Custom port
await server.start(port: 3000);
Auto port selection
If the requested port is busy, the server automatically tries the next available port (up to 100 attempts). You can listen for the actual port via the onStarted callback:
final server = NetLogsServer(
interceptor: interceptor,
onStarted: (port) {
print('Dashboard at http://localhost:$port');
// Show a SnackBar, toast, or notification
},
);
await server.start(); // starts on 8080, or 8081, etc.
Stop the server
await server.stop();
Request names
Give requests a friendly name so they're easy to identify in the log table:
await dio.get(
'/api/users',
options: Options(extra: {'requestName': 'Fetch Users'}),
);
await dio.post(
'/api/login',
data: {'email': 'user@example.com'},
options: Options(extra: {'requestName': 'Login'}),
);
When a name is set, it appears prominently in the table and detail panel instead of the raw URL.
Web UI
| Column | Description |
|---|---|
| # | Request counter |
| Method | Colored badge (GET/POST/PUT/DELETE/…) |
| URL / Name | Friendly name if set, otherwise host/path |
| Status | Colored badge (2xx/3xx/4xx/5xx/ERR) |
| Size | Response body size |
| Duration | Request round-trip time |
| Time | Local timestamp |
Click any row to open the detail panel with three tabs:
- Headers — request URL, method, duration, all request/response headers
- Payload — formatted and syntax-highlighted request body (JSON)
- Response/Error — formatted and syntax-highlighted response body (JSON)
Additional information
- Issues: Report bugs or request features on GitHub Issues.
- License: This project is licensed under the MIT License — see the LICENSE file for details.