Watchdog
A Flutter developer toolkit that streams HTTP requests, responses, BLoC lifecycle events, navigation, and app logs to a browser-based DevTools page in real-time. No IDE plugins, no native tooling, no account.
flutter run watchdog open
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ your app │◀────────│ browser tab │
│ Watchdog │ :8888 │ localhost │
└───────────────┘ └───────────────┘
2-minute quickstart
Five steps. Copy-paste each block as you go.
1. Add the dependency
pubspec.yaml:
dependencies:
watchdog: ^0.1.3
flutter pub get
2. Initialize before runApp
main.dart:
import 'package:flutter/widgets.dart';
import 'package:watchdog/watchdog.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Watchdog.initialize();
await Watchdog.start();
runApp(const MyApp());
}
That's the whole integration. Watchdog only runs in debug builds — release builds are a no-op, so it's safe to leave in.
3. Wire the observers where you already use Chopper / Navigator
Only add the lines you need. Skip the ones that don't apply.
// HTTP inspection (Chopper):
ChopperClient(interceptors: [Watchdog.chopperInterceptor]);
// Navigation events:
MaterialApp(navigatorObservers: [Watchdog.routeObserver]);
// DI registrations (GetIt) — after configureDependencies():
Watchdog.trackGetIt(getIt);
BLoC lifecycle is wired automatically by Watchdog.start() — no setup.
4. Install the CLI (once per machine)
dart pub global activate watchdog
Then add pub's bin directory to your PATH. Pick the block for your
shell (see PATH setup details if unsure):
macOS / Linux (zsh or bash)
echo 'export PATH="$PATH:$HOME/.pub-cache/bin"' >> ~/.zshrc
source ~/.zshrc
Use ~/.bashrc instead of ~/.zshrc if you're on bash.
Windows — Git Bash
echo 'watchdog() { "$(cygpath "$LOCALAPPDATA/Pub/Cache/bin/watchdog.bat")" "$@"; }' >> ~/.bashrc
source ~/.bashrc
Windows — PowerShell
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";$env:LOCALAPPDATA\Pub\Cache\bin", "User")
Close and reopen the terminal afterwards.
Verify:
watchdog version
5. Open DevTools
With the app running on a device or emulator:
watchdog open
Your browser opens http://localhost:8888. You're done.
What you get
- Network inspector — every Chopper HTTP request/response with headers, body, status, timing, and cURL export.
- BLoC lifecycle — creation, state changes, and closure of every Bloc and Cubit, with creation stack traces.
- Navigation — push, pop, replace, remove events with a live route stack.
- Structured logging — debug / info / warning / error / critical levels.
- WebSocket tracker — send, receive, and connection state events.
- GetIt scanner — broadcasts every DI registration.
- Cloud streaming — optionally mirror events to a remote server.
- Replay buffer — late-connecting browsers receive full event history.
Daily usage
watchdog open # the one you'll use 99% of the time
watchdog open --port 9000 # custom port
watchdog open --no-adb # iOS-only / real-WiFi (skip adb)
watchdog forward # set up port forwarding, no browser
watchdog devices # list adb devices
watchdog version # print CLI version
Convenience logging
Watchdog.debug('Cache miss for key=$key');
Watchdog.info('Driver connected');
Watchdog.warning('GPS accuracy degraded: ${accuracy}m');
Watchdog.error('Sync failed', error: e, stackTrace: st);
WebSocket tracking
Watchdog.socketTracker.trackSend(channel: 'wss://api.example.com/ws', data: payload);
Watchdog.socketTracker.trackReceive(channel: 'wss://api.example.com/ws', data: decoded);
Configuration
Pass a WatchdogConfig to initialize() to override defaults:
await Watchdog.initialize(
config: const WatchdogConfig(
apiBaseUrl: 'https://api.example.com',
enableLogging: true,
),
);
| Parameter | Default | Description |
|---|---|---|
apiBaseUrl |
null |
Shown in the DevTools header for environment ID |
port |
8888 |
Local server port |
host |
0.0.0.0 |
Bind address |
enableLogging |
true |
Enable log events in the Logs tab |
maskSensitiveHeaders |
true |
Mask Authorization headers in the UI |
replayBufferSize |
10000 |
Max events retained for late clients |
enabled |
null |
null = kDebugMode; true forces enable |
cloud |
null |
WatchdogCloudConfig for remote streaming |
Advanced
Custom logger — integrate your own logging backend
class MyLogger implements WatchdogLogger {
@override
void log(WatchdogLogLevel level, String message,
{String? title, Object? error, StackTrace? stackTrace}) {
// your implementation
}
}
await Watchdog.initialize(
dependencies: WatchdogDependencies(logger: MyLogger()),
);
Cloud streaming — mirror events to a remote server
await Watchdog.initialize(
config: const WatchdogConfig(
cloud: WatchdogCloudConfig(
serverUrl: 'wss://watchdog-cloud.example.com',
apiKey: 'your-api-key',
appName: 'my-app',
),
),
);
Bridge an existing project logger
AppLogger.attachBridge(Watchdog.bridge);
Troubleshooting
watchdog: command not found
The pub cache bin directory isn't on your PATH. Redo step 4.
Browser shows "This site can't be reached" / ERR_CONNECTION_REFUSED Three things to check, in order:
- The Flutter app is running on a device/emulator (not just built).
- You're on a debug build (
flutter runwithout--release). adb deviceslists your device. Ifadbisn't on PATH, install Android platform-tools or usewatchdog open --no-adbfor iOS.
adb forward failed: cannot bind listener
A previous forwarding is stuck. Run:
adb forward --remove-all && watchdog open
PATH setup details
dart pub global activate installs the watchdog executable into the
Dart pub cache, but does not add that directory to your PATH. Until
you do it yourself, typing watchdog won't find the binary.
The pub cache lives at:
- macOS / Linux:
~/.pub-cache/bin - Windows:
%LOCALAPPDATA%\Pub\Cache\bin
On Windows + Git Bash, simply adding that directory to PATH isn't
enough because pub installs the executable as watchdog.bat and Git Bash
doesn't auto-append .bat when resolving commands. That's why step 4's
Git Bash block defines a shell function that invokes the .bat file
directly — it works regardless of extension handling.
Public API summary
| Accessor | Type | Description |
|---|---|---|
Watchdog.initialize() |
Future<void> |
One-time setup |
Watchdog.start() |
Future<void> |
Opens server + cloud |
Watchdog.stop() |
Future<void> |
Pauses capture |
Watchdog.dispose() |
Future<void> |
Full teardown |
Watchdog.logger |
WatchdogLogger |
Active logger instance |
Watchdog.bridge |
WatchdogLoggerBridge |
Legacy logger adapter |
Watchdog.blocObserver |
WatchdogBlocObserver |
BLoC lifecycle observer |
Watchdog.routeObserver |
WatchdogRouteObserver |
Navigation observer |
Watchdog.chopperInterceptor |
WatchdogChopperInterceptor |
HTTP interceptor |
Watchdog.socketTracker |
WatchdogSocketTracker |
WebSocket tracker |
Watchdog.trackGetIt() |
void |
Scans GetIt container |
Watchdog.isInitialized |
bool |
Init state |
Watchdog.isRunning |
bool |
Server state |
License
MIT — see LICENSE.
Libraries
- watchdog
- Watchdog — Flutter developer toolkit.