Flutter API Tracker β‘
A production-ready, zero-boilerplate Flutter package that automatically tracks API calls and their call sequences. It intercepts all outgoing network traffic globally at the dart:io level β no modifications needed to your existing Dio, http, or HttpClient code.
π Features
| Feature | Description |
|---|---|
| π Zero-Config Interception | Uses HttpOverrides.global to catch all network traffic without touching your code. |
| π Session-Based Logging | API calls are grouped by session (one per app launch when enabled). |
| ποΈ SQLite Persistence | All sessions and logs are stored locally via sqflite. History survives app restarts. |
| π± Screen Tracking | Associates each API call with the screen it was triggered from. |
| π Search & Filter | Search logs by URL, method, status code, or screen name in real-time. |
| π΅οΈ Secret Activation | An invisible 6-tap gesture (configurable) reveals the debugger UI. |
| π§ HTML Email Reports | Export session summaries as professional HTML emails with .txt attachments. |
| π€ System Sharing | Share session logs as text files directly via the system share sheet. |
| π Session Management | Rename sessions for better organization or delete old ones to save space. |
| π Copy to Clipboard | Copy any full log entry to clipboard with a single tap. |
| πΎ Persistent Enable State | The enabled/disabled state is saved via shared_preferences and restored on next launch. |
| β‘ Performance Optimized | When disabled, all logging and database writes are completely skipped. |
| π Release Mode Safe | Disabled by default in Release builds unless you explicitly opt in. |
π¦ Installation
Add the dependency to your pubspec.yaml:
dependencies:
flutter_api_tracker: ^1.0.0
Then run:
flutter pub get
π οΈ Quick Start
Step 1 β Initialize in main()
Call ApiDebugger.initialize() before runApp(). You must call WidgetsFlutterBinding.ensureInitialized() first because the package uses sqflite and shared_preferences.
import 'package:flutter/material.dart';
import 'package:flutter_api_tracker/flutter_api_tracker.dart';
void main() async {
// CRITICAL: Must be called before any async work.
WidgetsFlutterBinding.ensureInitialized();
// Initialize the debugger with optional parameters.
await ApiDebugger.initialize(
enableInRelease: false, // Default: false. Set true to allow in production.
// Optional: SMTP configuration for email reports
smtpConfig: SmtpConfig(
server: 'smtp.gmail.com',
port: 587,
username: 'your-email@gmail.com',
password: 'your-app-password',
fromEmail: 'your-email@gmail.com',
defaultRecipients: [
const RecipientConfig(name: 'Dev Team', email: 'dev@example.com'),
const RecipientConfig(name: 'QA Team', email: 'qa@example.com'),
],
),
);
runApp(const MyApp());
}
Step 2 β Wrap your App
Wrap your root widget (or MaterialApp) with ApiDebuggerWrapper. This widget listens for the secret tap gesture to open the debugger UI.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ApiDebuggerWrapper(
child: MaterialApp(
title: 'My App',
// Add the navigator observer for automatic screen tracking.
navigatorObservers: [ApiDebugger.navigatorObserver()],
home: const MyHomePage(),
),
);
}
}
Step 3 β Track Screen Names (Recommended)
For best results, use ApiDebugger.route() instead of MaterialPageRoute when navigating. This automatically logs the widget's class name as the "Screen" for each API call made on that screen.
Navigator.push(
context,
ApiDebugger.route(const MyProfilePage()),
);
How it works:
ApiDebugger.route()creates aMaterialPageRoutewithRouteSettings(name: page.runtimeType.toString()). TheApiNavigatorObserverthen picks up this name and stores it in the singletonScreenTracker, which the HTTP interceptor reads when logging each request.
π₯ Advanced Usage
Programmatic Control
Control the debugger from anywhere in your code:
import 'package:flutter_api_tracker/flutter_api_tracker.dart';
// Enable logging (starts a new session, persists state)
await ApiDebugger.enable();
// Disable logging (persists state, clears active session)
await ApiDebugger.disable();
// Check current status
bool isActive = ApiDebugger.isEnabled;
// Open the Session List screen directly
ApiDebugger.open(context);
Custom Tap Trigger
Customize the number of taps required or provide your own trigger logic:
ApiDebuggerWrapper(
tapCount: 10, // Require 10 rapid taps instead of the default 6.
onTrigger: (BuildContext context) {
// Your custom logic here.
// Example: show a custom dialog before opening.
ApiDebugger.open(context);
},
child: const MyAppBody(),
)
Tap timeout: A tap sequence resets if there is more than a 2-second gap between taps.
Force-Override State on Launch
If you want to guarantee the debugger starts in a specific state (e.g., always enabled in debug builds, always disabled in staging):
await ApiDebugger.initialize(
initiallyEnabled: true, // Forces ON regardless of the persisted state.
);
Email Reporting & SMTP
To enable the "Send Email" feature, provide an SmtpConfig during initialization. You can also define defaultRecipients which will appear as selectable chips in the email form.
The exported email includes:
- Professional HTML Body: A summary of the session including total requests, success rate, and failure count.
- Custom Header: Session name, sender name, and timestamp.
- Detailed Attachment: A full
.txtlog file attached for deep inspection.
await ApiDebugger.initialize(
smtpConfig: SmtpConfig(
server: 'smtp.office365.com',
port: 587,
username: 'reports@company.com',
password: 'password123',
fromEmail: 'reports@company.com',
defaultRecipients: [
RecipientConfig(name: 'Lead Dev', email: 'lead@company.com'),
],
),
);
Sharing Logs
From the Log List screen, you can tap the Share icon in the AppBar. This generates a complete .txt report of all logs in that session and opens the system share sheet.
Files are automatically named using the format:
api_report_[session_name]_[mmddyyyy]_[hhmm].txt
Search & Filtering
Inside the Log List screen, tap the search icon to filter logs in real-time. You can filter by:
- URL: Matches any part of the endpoint path.
- Method: e.g.,
GET,POST. - Status Code: e.g.,
404,200. - Screen Name: The widget name where the call originated.
Session Management
To keep your logs organized:
- Rename: Open the Log List for a session, tap the menu (three dots), and select Edit Name.
- Delete: Single sessions can be deleted from the same menu.
- Clear All: Use the "sweep" icon on the main Session List screen to wipe all local data.
π Debugger UI Overview
The debugger UI consists of three interconnected screens:
ApiSessionListScreen ApiLogListScreen ApiLogDetailScreen
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β API Sessions β β Logs for Session β β Log Details β
β βββββββββββββββββ β β βββββββββββββββββ β β βββββββββββββββββ β
β β Session abc123 ββββΊ β GET /posts/1 200 ββββΊβ [Request] [Responseβ
β β Session def456 β β POST /posts 201 β β β
β β Session ghi789 β β DELETE /posts 404 β β URL, Method, Statusβ
β [Enable] [Clear] β β β β Headers, Body β
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
| Screen | Description |
|---|---|
| Session List | Shows all recorded sessions. Current session is highlighted with a pulsing green dot and primary colors. Each card shows the API count. Includes Toggle and "Clear All". |
| Log List | Shows all API calls in a session. Use the Search bar to filter. The AppBar shows the session name. Contains Email, Share, and Session Menu (Rename/Delete). |
| Log Detail | Two tabs: Request (URL, method, time, screen, headers, body) and Response (status code, headers, body). Features syntax highlighting and clipboard copy. |
ποΈ Data Models
ApiLogModel
Represents a single intercepted HTTP call.
| Property | Type | Description |
|---|---|---|
id |
String |
Unique UUID for the log entry. |
sessionId |
String |
The session this log belongs to. |
method |
String |
HTTP method (GET, POST, PUT, etc.). |
url |
String |
The full request URL. |
requestHeaders |
Map<String, String>? |
Request headers. |
requestBody |
dynamic |
Request body (auto-formatted if JSON). |
responseHeaders |
Map<String, String>? |
Response headers. |
responseBody |
dynamic |
Response body (auto-formatted if JSON). |
statusCode |
int? |
HTTP response status code. |
timestamp |
DateTime |
When the request was initiated. |
duration |
Duration |
How long the request took. |
screenName |
String? |
The screen that initiated the request. |
isError |
bool |
true if the status code indicates an error. |
ApiSessionModel
Represents a single debugging session (one per app launch when enabled).
| Property | Type | Description |
|---|---|---|
id |
String |
Unique UUID for this session. |
startTime |
DateTime |
When this session was started. |
β Limitations
- π No Web Support:
HttpOverridesanddart:ioare not available on Flutter Web. The package silently no-ops on Web. - π¦ Interception Level: Intercepts at the raw
dart:ioHttpClientlevel. It captures data after your app processes it but before it's sent over the wire. This means multipart form data bodies may not be human-readable. - β οΈ Sensitive Data: All request/response data, including auth tokens and payloads, is stored in the local SQLite database. Do not enable
enableInRelease: truein production apps that handle sensitive user data without a clear security review.
π Safety & Performance
- SSL/TLS Safe: The package does not interfere with certificate validation, SSL handshakes, or
badCertificateCallback. - No Overhead When Disabled: All interception code returns immediately when
isEnabledisfalse. - Session Memory Cap: The in-memory log list is capped at 200 entries per session to prevent excessive memory usage. Older entries roll off but remain in the database.
- Singleton Services:
ApiLogServiceandApiDatabaseServiceare singletons, ensuring a single shared state and database connection.
π€ Contributing
Contributions are welcome! Please feel free to open an issue or submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
Created & Maintained By
This package is created and maintained by Conversantech.
License
This project is licensed under the MIT License - see the LICENSE file for details. Copyright (c) 2026 Conversantech.
Libraries
- core/http_overrides
- core/logging_http_client
- core/logging_http_request
- core/logging_http_response
- flutter_api_tracker
- models/api_log_model
- models/api_session_model
- models/smtp_config
- services/api_database_service
- services/api_log_service
- services/screen_tracker
- ui/api_log_detail_screen
- ui/api_log_list_screen
- ui/api_session_list_screen
- widgets/api_debugger_wrapper