Documentation
Mobile
Web
TV

All but React Native are in beta.

Desktop App
docs

Images

Inspect images rendered through BuoyImage, including their load timing, decoded dimensions, displayed size, and available cache information. Plain Image widgets are not captured automatically.

every image, in 72 seconds

The film and the demo show the React Native tool, and the demo uses mock data. Use the Flutter setup and feature descriptions below for supported behavior; the demo does not establish Flutter feature parity.

Inspect example image loads

1 / 6

This interactive demo uses generated image events. Real capture depends on supported image hooks; some native loading paths may not appear.

9:41
Loading live demo…
Mock image loads, real component — the same code that renders in your app. Step through the tour, or just start tapping.

Installation

pub
flutter pub add buoy_images

Flutter has no app-wide Image decorator hook, so capture is opt-in at the widget level — use BuoyImage in place of Image / CachedNetworkImage:

dart
import 'package:flutter/widgets.dart';
import 'package:buoy_images/buoy_images.dart';

BuoyImage(
  provider: const NetworkImage('https://example.com/image.png'),
  width: 120,
  height: 120,
)
import 'package:flutter/widgets.dart';
import 'package:buoy_images/buoy_images.dart';

BuoyImage(
  provider: const NetworkImage('https://example.com/image.png'),
  width: 120,
  height: 120,
)

Replace the example URL with an image your app can load. For a standalone install, call registerBuoyImages() before mounting the core widget; the umbrella registers it for you.

It wraps your ImageProvider, measures the rendered box for the oversize audit, and owns the props so reload/retry and simulations work.


What You Can Do

  • Inspect captured image loads — thumbnail, source URL, load time, decoded dimensions, status. Tap for the full detail view.
  • Inspect available cache information — verdicts depend on the ImageProvider. A provider without disk-cache reporting cannot establish a disk-cache hit.
  • Catch oversized sources — decoded pixels compared against the laid-out size × device pixel ratio, Lighthouse-style, with the estimated wasted decoded memory and the exact dimensions you should serve instead.
  • Catch upscaled (blurry) sources too — a tiny thumbnail stretched into a large box gets flagged the other way.
  • Track decoded memory — estimated decoded-bitmap bytes per image and totaled, so you catch ballooning before the OOM crash.
  • Diagnose failures — every failure captured with the error message and the HTTP status where available.
  • Reproduce image bugs — per-image hard reload / retry, plus simulation overrides: force error / loading / blank / URL swap, and app-wide offline / cold-start / blank-images modes.

How it works

Flutter has no app-wide Image decorator hook like React Native. Capture is opt-in: wrap each load in BuoyImage, which instruments your ImageProvider, watches layout size for the oversize audit, and owns reload / retry / simulation props.

Buoy's own UI is excluded from capture — the tool never appears in its own registry.

Coverage notes

  • Only widgets wrapped in BuoyImage appear in the registry — plain Image.network / CachedNetworkImage without the wrapper stay invisible.
  • Cache verdicts depend on the provider (memory / disk / network) as reported through the instrumented load path.
  • Decoded-memory numbers are estimates (width × height × 4 bytes) — the same math platforms use for RGBA bitmaps.

Desktop & AI

The same live registry streams to Buoy Desktop — the full tool (list, detail, simulations, mass actions) on a big screen. And with the MCP server, an agent can list every load with get_images, reload or retry with image_action, and flip failure simulations with set_image_simulation.


What's Next


FAQ

Why can't a network inspector tell me why a Flutter image is slow?

Image HTTP traffic in Flutter is fetched by dart:io image loaders and never surfaces the layout size or cache origin an inspector needs. Buoy's registry records each load's cache verdict (memory, disk, or network), its timing, decoded size versus displayed size, and the exact reason it failed.

What do I have to change to capture image loads?

Flutter has no app-wide Image decorator hook, so capture is opt-in per widget: use BuoyImage(provider: ...) in place of Image or CachedNetworkImage. It wraps your ImageProvider and measures the rendered box for the oversize audit.

How do I find images that waste memory?

Decoded pixels are compared against the laid-out size × device pixel ratio, Lighthouse-style, with the estimated wasted decoded bytes and the dimensions you should serve instead. Tiny sources stretched into a large box are flagged the other way, as upscaled.