DEV Community

Jaimin Raval
Jaimin Raval

Posted on

I Got Tired of QA Sending Me "It Broke Again" Screenshots. So I Built This.

You know that moment when your QA lead sends you a WhatsApp message at 11 PM that just says:

"API not working again 🙂"

No logs. No steps to reproduce. No device info. Just vibes and a slightly passive-aggressive emoji.
I've been that developer. Many times. And every time, I'd open Android Studio, ask them to reproduce it while I watched the console, squint at a 400-line log dump, and eventually find one line that mattered.
This has to stop.

The problem with Flutter debugging
Flutter is incredible for building UIs. But the debug experience — specifically for non-developer stakeholders like QA engineers and product managers — is genuinely broken.
Here's what typically happens on a Flutter project:

QA finds a bug
QA sends a screenshot (sometimes)
Developer asks: "What was the API response?"
QA doesn't know. They just saw a spinner and then nothing.
Developer asks: "Can you reproduce it?"
QA tries. It doesn't reproduce. The bug disappears into the void.

Meanwhile, on the web, you have browser DevTools. On React Native, you have Flipper. On iOS, you have the Instruments suite.
Flutter has... print().

What I actually wanted
I wanted one thing: a debug overlay that QA can use themselves, without needing a connected Mac or developer standing next to them.
Specifically:

See every API request and response in real time
Inspect device info, app version, connectivity
See what the app was doing before the bug happened
Generate a report they can paste directly into Jira

So I built it. It's called flutter_blackbox.

What it does
flutter_blackbox is an in-app debug overlay for Flutter. Shake your device (or tap a floating button) and a full debug panel slides up. No computer attached. No build flags. No special setup.
Here's what's inside:

🌐 Network Inspector
Every HTTP request your app makes — headers, request body, response body, status code, timing — captured in real time. Works with Dio and the http package.
No more "what did the API return?" conversations.

📋 Live Logs
Auto-captures every print() and debugPrint() call. Also supports manual logging with levels (info, warning, error) and tags. All filterable.

Performance Monitor
Live FPS graph. Jank detection. Memory alerts. See exactly when your app starts struggling.

🔄 Widget Rebuild Tracker
Toggle AUTO mode and it tracks every widget rebuild automatically. Sorted by rebuild count, heat-colored. Find your worst offenders in 10 seconds.

💾 Storage Inspector
Browse, search, edit, and delete SharedPreferences, GetStorage, or Hive keys — directly from the overlay. Sensitive keys like token, password, jwt are auto-redacted.

🔌 Socket.IO Inspector
Auto-captures all incoming Socket.IO events. Zero code changes to your socket layer.

📝 One-Tap QA Reports
This is the feature that changed my team's workflow.
QA taps the QA tab, types a bug name, hits Generate Report. BlackBox compiles a Markdown report with:

Screenshot
Device info (model, OS, DPI, connectivity)
User journey (every route change and tap leading up to the bug)
All failed network requests with full payloads
Recent logs
Any crash stack traces

One tap Copy → paste into GitHub Issues, Jira, Linear, or Slack.
My QA lead went from "it broke again 🙂" to sending me full reproduction reports with API responses included. This is real.

Zero runtime cost — for real
Everything compiles out in release builds via Dart's tree-shaker and kDebugMode. BlackBox doesn't exist in your production APK.
The package itself is 63 KB with no optional dependencies bundled.

The part I'm most proud of: the CLI
Here's the thing about debug overlay packages — they usually require you to install their HTTP client, their logger, their storage solution. Which means your app gets heavier and you're locked into their choices.
BlackBox does it differently.
It ships with a built-in CLI that reads your pubspec.yaml, detects what libraries you already use, and generates the adapter code for your project:
bashdart run flutter_blackbox:init --generate

`Output:
🐞 BlackBox Init — Auto-detecting your dependencies...

✅ Found dio → Dio HTTP client
⬚ http → not found, skipping
✅ Found shared_preferences → SharedPreferences

✨ 2 adapter(s) detected!
📝 Generated: lib/blackbox_adapters.dart
You get a generated blackbox_adapters.dart tailored to your project. If you don't use http, you don't get the http adapter. Zero bloat.
This means BlackBox observes your existing code through built-in extension points (Dio interceptors, http client wrappers, SharedPreferences hooks) — it never modifies your trusted code.`

Integration is 3 steps

bash# Step 1
flutter pub add flutter_blackbox
Enter fullscreen mode Exit fullscreen mode
# Step 2
dart run flutter_blackbox:init --generate
Enter fullscreen mode Exit fullscreen mode
# Step 3: Update main.dart
dartimport 'package:flutter/foundation.dart';
import 'package:flutter_blackbox/flutter_blackbox.dart';
import 'blackbox_adapters.dart'; // ← generated by CLI

void main() {
  BlackBox.setup(
    httpAdapters: [DioBlackBoxAdapter(dio)],
    storageAdapters: [SharedPrefsStorageAdapter()],
    trigger: const BlackBoxTrigger.shake(), // or .floatingButton()
    enabled: kDebugMode,
  );
  runApp(const BlackBoxOverlay(child: MyApp()));
}
Enter fullscreen mode Exit fullscreen mode

That's it. Your existing Dio calls, socket events, and SharedPreferences are now fully observable.

What changed on my team
Before BlackBox:

QA files a vague bug report
Developer asks for reproduction steps
2–3 back-and-forth messages
Developer eventually reproduces it locally
Developer fixes it, probably

After BlackBox:

QA reproduces the bug
QA generates report (one tap)
Report lands in Jira with full API payload and device state
Developer fixes it in half the time

The back-and-forth is gone. The "it doesn't reproduce for me" problem is mostly gone. The passive-aggressive emojis are... still there. But at least they come with data now.

What's new in v0.5.0 — Crashlytics & Sentry integration
The biggest ask from the community after launch was: "Can BlackBox forward crashes to our existing monitoring tools?"
v0.5.0 ships the BlackBoxObserver API. It lets professional teams pipe BlackBox telemetry directly into Crashlytics, Sentry, Datadog, or any custom Slack webhook — without breaking the zero-dependency rule.

dartBlackBox.setup(
  observers: [
    BlackBoxObserver(
      onCrash: (crash) {
        FirebaseCrashlytics.instance.recordError(
          crash.error,
          crash.stackTrace,
          reason: crash.toFormattedString(), // one-liner readable payload
        );
      },
      onNetworkError: (req, res) {
        Sentry.captureMessage('API failed: ${req.url}${res?.statusCode}');
      },
    ),
  ],
  // ...rest of setup
);
Enter fullscreen mode Exit fullscreen mode

If you use firebase_crashlytics, the CLI now detects it automatically and generates a CrashlyticsObserver implementation pre-tagged for easy filtering in the Firebase dashboard:

bashdart run flutter_blackbox:init --generate

✅ Found firebase_crashlytics → CrashlyticsObserver

📝 Generated: lib/blackbox_adapters.dart

There's also a small but important UX fix: the Storage Inspector now shows a confirmation dialog before "Clear All" — because accidentally wiping SharedPreferences on a client's device during a demo is not a great look.

What's next
The package is actively maintained. On the roadmap:

GraphQL request inspector
Network throttling presets (simulate 3G, offline)
VS Code extension for report visualization

Try it
yamldependencies:
flutter_blackbox: ^0.5.0

pub.dev
GitHub

If it saves you one "it broke again 🙂" conversation, leave a like on pub.dev. It helps other Flutter devs find it.

Built by a Flutter developer who got tired of standing next to QA with a MacBook. Questions and feedback welcome in the comments.

Top comments (0)